Skip to content

feat: add worker custom trigger type to iii-worker-ops#1683

Merged
sergiofilhowz merged 2 commits into
mainfrom
feat/skills
May 25, 2026
Merged

feat: add worker custom trigger type to iii-worker-ops#1683
sergiofilhowz merged 2 commits into
mainfrom
feat/skills

Conversation

@sergiofilhowz
Copy link
Copy Markdown
Contributor

@sergiofilhowz sergiofilhowz commented May 23, 2026

Add worker custom trigger type to iii-worker-ops

Register a new SDK-callable trigger type, worker, so any worker can subscribe to the lifecycle of every worker::* op (add, remove, update, start, stop, clear) without polling worker::list. Subscribers narrow what they receive via filter fields on WorkerTriggerConfig (operations / stages / workers), and the daemon fans typed WorkerCallRequest payloads out fire-and-forget so a slow subscriber can never stall an op.

Summary

  • New trigger type worker registered by iii_worker::cli::worker_manager_daemon. trigger_request_format = WorkerTriggerConfig (subscriber filters), call_request_format = WorkerCallRequest (event payload).
  • Stage events on every mutating opcore/{add,remove,update,start,stop,clear}.rs now emit Started → Stage(verb-ing) → Stage(verb-ed)|Done on success and Started → Stage(verb-ing) → Failed { error } on shim error.
  • WorkerOpEvent::Failed new variant so terminal failures flow through the same EventSink as Done.
  • IIIEventSink bridges WorkerOpEventiii.trigger(fn_id, payload, Void) for every matching subscriber. Single dispatcher task per sink (mpsc-serialized) so wire order matches emit order — fixes a race where multi-thread runtimes delivered done before downloaded.
  • Skill docs — new new_skills/worker/skills/worker/events.md how-to plus per-op cross-links (add, remove, update, start, stop, clear) and a new "trigger type" section in index.md.
  • End-to-end test — in-process: EngineBuilder::serve() + daemon spawned as a tokio task + three subscribers exercising the filter matrix + iii.trigger("worker::add", iii-http).

Filter semantics

WorkerTriggerConfig has three optional Vec<…> fields:

Field Values Meaning
operations add / remove / update / start / stop / clear subset to subscribe to
stages started / downloading / downloaded / removing / updating / starting / stopping / clearing / done / failed subset to subscribe to
workers exact worker names subset to subscribe to
  • AND across fields, OR within a vector.
  • None and Some(vec![]) are both wildcards.

The lead use case — "notify when iii-http finishes downloading":

{ "operations": ["add"], "stages": ["downloaded"] }

<!-- This is an auto-generated comment: release notes by coderabbit.ai -->

## Summary by CodeRabbit

## Release Notes

* **New Features**
  * Added `worker` custom trigger type for subscribing to worker lifecycle events with filtering by operation, stage, and worker name.
  * Enhanced worker operations with granular lifecycle event emission, including stage progression and failure reporting.

* **Documentation**
  * Added comprehensive documentation for all worker operations and lifecycle events.
  * Added complete documentation for sandbox operations and usage examples.

<!-- review_stack_entry_start -->

[![Review Change Stack](https://storage.googleapis.com/coderabbit_public_assets/review-stack-in-coderabbit-ui.svg)](https://app.coderabbit.ai/change-stack/iii-hq/iii/pull/1683?utm_source=github_walkthrough&utm_medium=github&utm_campaign=change_stack)

<!-- review_stack_entry_end -->

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

@vercel
Copy link
Copy Markdown
Contributor

vercel Bot commented May 23, 2026

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

Project Deployment Actions Updated (UTC)
iii-website Ready Ready Preview, Comment May 23, 2026 12:09am

Request Review

@sergiofilhowz sergiofilhowz changed the title feat: adding reactive triggers to workers events feat: add worker custom trigger type to iii-worker-ops May 23, 2026
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 23, 2026

📝 Walkthrough

Walkthrough

This PR adds a custom worker trigger system that emits typed lifecycle events for worker operations, integrates it into the daemon, enhances all worker operations with granular stage and failure events, and validates the end-to-end flow with an in-process integration test. It also includes comprehensive documentation for worker and sandbox operations.

Changes

Worker Trigger System

Layer / File(s) Summary
Event type extension
crates/iii-worker/src/core/events.rs
WorkerOpEvent enum gains a Failed variant carrying op, worker name, and error string.
Worker trigger implementation and filter semantics
crates/iii-worker/src/cli/worker_trigger.rs
New module implementing the complete trigger system: wire-format types (WorkerOperation, WorkerStage, WorkerCallRequest), subscriber filter configuration with AND/OR semantics, trigger handler for registration/unregistration with JSON config parsing, IIIEventSink for event-to-request translation and fan-out via SDK, and comprehensive unit/integration tests.
Daemon trigger registration and wiring
crates/iii-worker/src/cli/mod.rs, crates/iii-worker/src/cli/worker_manager_daemon.rs
Daemon exports worker_trigger module, registers the "worker" trigger type, constructs shared subscriptions map, creates an IIIEventSink, and routes all mutating operations (add, remove, update, start, stop, clear) through the sink instead of NullSink.
Worker operation lifecycle event emission
crates/iii-worker/src/core/{add,clear,remove,start,stop,update}.rs
All operations now emit consistent event sequences: Started → Stage(phase_name) → either Failed(error) or Done. Tests validate exact event order and content for success and failure paths.
CLI Failed event output
crates/iii-worker/src/cli/stderr_sink.rs
StderrSink now renders WorkerOpEvent::Failed with red error prefix and worker name.
End-to-end integration test
engine/tests/worker_trigger_e2e.rs, engine/Cargo.toml
In-process test boots engine and daemon, registers subscribers with different filter configs, triggers worker::add, validates lifecycle event sequences, field values, and filter matching. Includes test helpers for environment, port, and event coordination.
Configuration and dependencies
engine/config.yaml, engine/Cargo.toml
Cargo.toml adds iii-worker dev dependency; config.yaml relocates iii-http worker block and adds CORS configuration.

Worker and Sandbox Documentation

Layer / File(s) Summary
Worker operation documentation
new_skills/worker/index.md, new_skills/worker/skills/worker/{add,clear,list,remove,schema,start,stop,update}.md
Index page and per-operation how-tos describing usage, input/output schemas, side effects, and error codes for all worker operations.
Worker trigger events documentation
new_skills/worker/skills/worker/events.md
Describes subscription semantics, filter configuration, typed event payload structure, per-operation stage matrices for success/failure paths, and example subscriber configurations.
Sandbox operation documentation
new_skills/sandbox/index.md, new_skills/sandbox/skills/sandbox/{create,exec,list,stop}.md
Index page and per-operation how-tos for ephemeral microVM operations with input/output contracts, side effects, and error codes.

🎯 4 (Complex) | ⏱️ ~60 minutes

Suggested reviewers

  • guibeira
  • andersonleal

🐰 A trigger springs to life,
Events dance through subscriptions bright,
Workers tell their tale,
Progress stages hail,
Daemon wisdom shines so right!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 79.41% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: adding a new worker custom trigger type to the iii-worker-ops daemon for subscribing to worker lifecycle events.
Description check ✅ Passed The pull request description is well-structured with comprehensive information covering what was changed, why it was changed, and implementation details including filter semantics and use cases.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/skills

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 7

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@crates/iii-worker/src/cli/worker_trigger.rs`:
- Around line 341-403: The event_to_request mapping currently hardcodes
source/version/status to None for all WorkerOpEvent branches, which drops
terminal add/update metadata; update event_to_request (the match arms that
construct WorkerCallRequest for WorkerOpEvent::Started, ::Stage, ::PullProgress,
::Done, ::Failed, etc.) to extract and forward the event's source, version, and
status fields (when present on the incoming WorkerOpEvent variants) into
WorkerCallRequest.source, .version, and .status instead of setting them to None;
keep existing conversions (op_from_str, stage_from_str) and the error mapping
for WorkerErrorPayload unchanged.

In `@engine/config.yaml`:
- Around line 196-204: The config currently uses a wildcard in
cors.allowed_origins which is insecure; change cors.allowed_origins to be an
explicit, env-configurable allowlist (e.g., read CORS_ALLOWED_ORIGINS and parse
as CSV) and remove the default '*' so production defaults to an empty or
specific host list (localhost only for dev). Update the loader that reads
cors.allowed_origins and the related consumers (keys: cors.allowed_origins,
cors.allowed_methods) to accept the env override and to only allow wildcard when
an explicit DEV flag or environment (e.g., NODE_ENV=development or
CORS_ALLOW_WILDCARD=true) is set; keep allowed_methods explicit but consider
narrowing defaults if needed. Ensure validation fails or warns if
allowed_origins is empty in production mode so deployers must configure a safe
origin list.

In `@engine/tests/worker_trigger_e2e.rs`:
- Around line 416-433: The fixed 250ms sleep before draining events
(tokio::time::sleep(Duration::from_millis(250)).await) makes the checks flaky;
replace it with bounded timeout-based receives on the subscribers' channels: use
tokio::time::timeout(...) around downloaded_subscriber.rx.recv() to await the
expected event and assert its contents (stage/operation/worker) when
Some(Ok/Value) is returned, and use tokio::time::timeout(...) around
remove_subscriber.rx.recv() and assert it returns Err(elapsed) or None within
the timeout to confirm no removal event arrived; update or remove usages of
drain_immediate to use these timeout recv checks so CI variance won’t cause
flakes.

In `@new_skills/sandbox/skills/sandbox/create.md`:
- Line 97: Replace the CLI-style guidance text that currently says "iii worker
add <image-ref>" with the canonical primitive identifier "worker::add" so the
S101 message uses documented primitive IDs; locate the S101 string ("rootfs
missing on disk — run iii worker add <image-ref> first.") in the create.md
content and update it to read something like "rootfs missing on disk — run
worker::add first." to conform to the primitives documentation.

In `@new_skills/worker/skills/worker/events.md`:
- Around line 194-196: The docs incorrectly label a malformed
WorkerTriggerConfig as W101; remove the W101 mapping in the paragraph
referencing WorkerTriggerConfig and replace it with the correct
outcome/identifier `trigger_registration_failed`, update the example sentence to
state that the trigger registration is rejected with
`trigger_registration_failed` (and nothing is stored), and ensure the text
references the WorkerTriggerConfig primitive exactly as defined in the docs so
SDK consumers see the correct contract.

In `@new_skills/worker/skills/worker/schema.md`:
- Around line 41-42: The inline comment for the "function_id" example
incorrectly calls "worker::add" a "dotted op id"; update the comment to
reference the engine convention and say something like "::-separated function
id" or "`::`-separated function id" so the example matches naming guidance
(e.g., refer to "worker::add" and the :: separator in the comment near the
"function_id" field).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 1fd665f3-45ef-4036-a55a-7deb4841d4a8

📥 Commits

Reviewing files that changed from the base of the PR and between 3050368 and 597efab.

⛔ Files ignored due to path filters (2)
  • Cargo.lock is excluded by !**/*.lock
  • engine/iii.lock is excluded by !**/*.lock
📒 Files selected for processing (29)
  • crates/iii-worker/src/cli/mod.rs
  • crates/iii-worker/src/cli/stderr_sink.rs
  • crates/iii-worker/src/cli/worker_manager_daemon.rs
  • crates/iii-worker/src/cli/worker_trigger.rs
  • crates/iii-worker/src/core/add.rs
  • crates/iii-worker/src/core/clear.rs
  • crates/iii-worker/src/core/events.rs
  • crates/iii-worker/src/core/remove.rs
  • crates/iii-worker/src/core/start.rs
  • crates/iii-worker/src/core/stop.rs
  • crates/iii-worker/src/core/update.rs
  • engine/Cargo.toml
  • engine/config.yaml
  • engine/tests/worker_trigger_e2e.rs
  • new_skills/sandbox/index.md
  • new_skills/sandbox/skills/sandbox/create.md
  • new_skills/sandbox/skills/sandbox/exec.md
  • new_skills/sandbox/skills/sandbox/list.md
  • new_skills/sandbox/skills/sandbox/stop.md
  • new_skills/worker/index.md
  • new_skills/worker/skills/worker/add.md
  • new_skills/worker/skills/worker/clear.md
  • new_skills/worker/skills/worker/events.md
  • new_skills/worker/skills/worker/list.md
  • new_skills/worker/skills/worker/remove.md
  • new_skills/worker/skills/worker/schema.md
  • new_skills/worker/skills/worker/start.md
  • new_skills/worker/skills/worker/stop.md
  • new_skills/worker/skills/worker/update.md

Comment on lines +341 to +403
WorkerOpEvent::Started { op, worker } => Some(WorkerCallRequest {
operation: op_from_str(op)?,
worker,
stage: WorkerStage::Started,
timestamp_ms,
source: None,
version: None,
status: None,
caller_mode,
progress: None,
error: None,
}),
WorkerOpEvent::Stage { op, stage, worker } => Some(WorkerCallRequest {
operation: op_from_str(op)?,
worker,
stage: stage_from_str(stage)?,
timestamp_ms,
source: None,
version: None,
status: None,
caller_mode,
progress: None,
error: None,
}),
WorkerOpEvent::PullProgress { worker, fraction } => Some(WorkerCallRequest {
operation: WorkerOperation::Add,
worker,
stage: WorkerStage::Downloading,
timestamp_ms,
source: None,
version: None,
status: None,
caller_mode,
progress: Some(fraction),
error: None,
}),
WorkerOpEvent::Done { op, worker } => Some(WorkerCallRequest {
operation: op_from_str(op)?,
worker,
stage: WorkerStage::Done,
timestamp_ms,
source: None,
version: None,
status: None,
caller_mode,
progress: None,
error: None,
}),
WorkerOpEvent::Failed { op, worker, error } => Some(WorkerCallRequest {
operation: op_from_str(op)?,
worker,
stage: WorkerStage::Failed,
timestamp_ms,
source: None,
version: None,
status: None,
caller_mode,
progress: None,
error: Some(WorkerErrorPayload {
code: "W900".to_string(),
message: error,
}),
}),
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.

⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

event_to_request drops documented terminal metadata for add/update flows.

All branches currently hardcode source, version, and status to None. This prevents subscribers from receiving required terminal add/update payload fields (status and version when available), even though WorkerCallRequest models them.

As per coding guidelines, new_skills/worker/skills/worker/add.md and new_skills/worker/skills/worker/events.md require terminal add payloads to surface status and version (when available) under the typed event contract.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/iii-worker/src/cli/worker_trigger.rs` around lines 341 - 403, The
event_to_request mapping currently hardcodes source/version/status to None for
all WorkerOpEvent branches, which drops terminal add/update metadata; update
event_to_request (the match arms that construct WorkerCallRequest for
WorkerOpEvent::Started, ::Stage, ::PullProgress, ::Done, ::Failed, etc.) to
extract and forward the event's source, version, and status fields (when present
on the incoming WorkerOpEvent variants) into WorkerCallRequest.source, .version,
and .status instead of setting them to None; keep existing conversions
(op_from_str, stage_from_str) and the error mapping for WorkerErrorPayload
unchanged.

Comment on lines +27 to +34
/// Terminal failure event. Emitted by orchestrators before
/// returning an `Err` from the host shim so subscribers see the
/// lifecycle terminate cleanly alongside the typed error envelope.
Failed {
op: &'static str,
worker: String,
error: String,
},
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.

⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

Preserve structured WorkerOpError data in WorkerOpEvent::Failed.

WorkerOpEvent::Failed currently stores only error: String, which forces downstream payload mapping to lose concrete Wxxx codes and emit generic failures. This breaks the typed failure contract expected by subscribers.

As per coding guidelines, new_skills/worker/index.md defines the WorkerOpError envelope with {"type":"WorkerOpError","code":"Wxxx",...} and expected W codes.

Comment thread engine/config.yaml
Comment on lines +196 to +204
cors:
allowed_origins:
- '*'
allowed_methods:
- GET
- POST
- PUT
- DELETE
- OPTIONS
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.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Avoid wildcard CORS origin as the default in engine config.

Allowing '*' with broad HTTP methods weakens the default security baseline. Please default to an explicit allowlist (env-configurable), and keep wildcard-only for local/dev overrides.

Suggested hardening
       cors:
         allowed_origins:
-        - '*'
+        - ${III_HTTP_ALLOWED_ORIGIN:http://localhost:3000}
         allowed_methods:
         - GET
         - POST
         - PUT
         - DELETE
         - OPTIONS
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
cors:
allowed_origins:
- '*'
allowed_methods:
- GET
- POST
- PUT
- DELETE
- OPTIONS
cors:
allowed_origins:
- ${III_HTTP_ALLOWED_ORIGIN:http://localhost:3000}
allowed_methods:
- GET
- POST
- PUT
- DELETE
- OPTIONS
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@engine/config.yaml` around lines 196 - 204, The config currently uses a
wildcard in cors.allowed_origins which is insecure; change cors.allowed_origins
to be an explicit, env-configurable allowlist (e.g., read CORS_ALLOWED_ORIGINS
and parse as CSV) and remove the default '*' so production defaults to an empty
or specific host list (localhost only for dev). Update the loader that reads
cors.allowed_origins and the related consumers (keys: cors.allowed_origins,
cors.allowed_methods) to accept the env override and to only allow wildcard when
an explicit DEV flag or environment (e.g., NODE_ENV=development or
CORS_ALLOW_WILDCARD=true) is set; keep allowed_methods explicit but consider
narrowing defaults if needed. Ensure validation fails or warns if
allowed_origins is empty in production mode so deployers must configure a safe
origin list.

Comment on lines +416 to +433
tokio::time::sleep(Duration::from_millis(250)).await;

let downloaded_events = drain_immediate(&mut downloaded_subscriber.rx);
assert_eq!(
downloaded_events.len(),
1,
"stages:[downloaded] subscriber should receive exactly one event, got {n}: {downloaded_events:#?}",
n = downloaded_events.len()
);
assert_eq!(downloaded_events[0]["stage"], "downloaded");
assert_eq!(downloaded_events[0]["operation"], "add");
assert_eq!(downloaded_events[0]["worker"], "iii-http");

let remove_events = drain_immediate(&mut remove_subscriber.rx);
assert!(
remove_events.is_empty(),
"operations:[remove] subscriber should receive zero events from an `add`, got: {remove_events:#?}"
);
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.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Replace fixed-delay fan-out checks with timeout-based receives.

The 250ms sleep on Line 416 makes this assertion block timing-sensitive and can intermittently fail on slower CI executors. Use bounded timeout(..., rx.recv()) checks so delivery latency variance doesn’t create flakes.

Suggested direction
-    tokio::time::sleep(Duration::from_millis(250)).await;
-
-    let downloaded_events = drain_immediate(&mut downloaded_subscriber.rx);
+    let first_downloaded = tokio::time::timeout(
+        Duration::from_secs(2),
+        downloaded_subscriber.rx.recv(),
+    )
+    .await
+    .expect("timed out waiting for downloaded event")
+    .expect("downloaded subscriber channel closed unexpectedly");
+    let mut downloaded_events = vec![first_downloaded];
+    downloaded_events.extend(drain_immediate(&mut downloaded_subscriber.rx));
@@
-    let remove_events = drain_immediate(&mut remove_subscriber.rx);
-    assert!(
-        remove_events.is_empty(),
-        "operations:[remove] subscriber should receive zero events from an `add`, got: {remove_events:#?}"
-    );
+    let remove_probe = tokio::time::timeout(Duration::from_millis(500), remove_subscriber.rx.recv()).await;
+    assert!(
+        matches!(remove_probe, Err(_) | Ok(None)),
+        "operations:[remove] subscriber should receive zero events from an `add`, got: {remove_probe:?}"
+    );
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@engine/tests/worker_trigger_e2e.rs` around lines 416 - 433, The fixed 250ms
sleep before draining events
(tokio::time::sleep(Duration::from_millis(250)).await) makes the checks flaky;
replace it with bounded timeout-based receives on the subscribers' channels: use
tokio::time::timeout(...) around downloaded_subscriber.rx.recv() to await the
expected event and assert its contents (stage/operation/worker) when
Some(Ok/Value) is returned, and use tokio::time::timeout(...) around
remove_subscriber.rx.recv() and assert it returns Err(elapsed) or None within
the timeout to confirm no removal event arrived; update or remove usages of
drain_immediate to use these timeout recv checks so CI variance won’t cause
flakes.


- **S001** invalid request (malformed `image`, missing required field).
- **S100** image not in catalog. Add it to the catalog or use a preset.
- **S101** rootfs missing on disk — run `iii worker add <image-ref>` first.
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.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Use canonical primitive ID instead of CLI syntax in error guidance.

Line 97 should reference worker::add (primitive) rather than iii worker add <image-ref> to stay consistent with documented primitives.

Suggested edit
-- **S101** rootfs missing on disk — run `iii worker add <image-ref>` first.
+- **S101** rootfs missing on disk — run [`worker::add`](iii://worker/add) for that image first.

As per coding guidelines: "**/*.md*: Ensure all references to primitives reflect those defined in docs/".

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
- **S101** rootfs missing on disk — run `iii worker add <image-ref>` first.
- **S101** rootfs missing on disk — run [`worker::add`](iii://worker/add) for that image first.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@new_skills/sandbox/skills/sandbox/create.md` at line 97, Replace the
CLI-style guidance text that currently says "iii worker add <image-ref>" with
the canonical primitive identifier "worker::add" so the S101 message uses
documented primitive IDs; locate the S101 string ("rootfs missing on disk — run
iii worker add <image-ref> first.") in the create.md content and update it to
read something like "rootfs missing on disk — run worker::add first." to conform
to the primitives documentation.

Comment on lines +194 to +196
- **W101** the `WorkerTriggerConfig` payload was malformed (e.g.
`operations: "add"` instead of `["add"]`). The trigger registration
is rejected with `trigger_registration_failed`; nothing is stored.
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.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Malformed WorkerTriggerConfig should not be documented as W101.

This error path is a trigger-registration failure (trigger_registration_failed), not a WorkerOpError code. Please remove W101 mapping here to avoid contract drift for SDK consumers.

As per coding guidelines: "**/.md: Ensure all references to primitives reflect those defined in docs/".

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@new_skills/worker/skills/worker/events.md` around lines 194 - 196, The docs
incorrectly label a malformed WorkerTriggerConfig as W101; remove the W101
mapping in the paragraph referencing WorkerTriggerConfig and replace it with the
correct outcome/identifier `trigger_registration_failed`, update the example
sentence to state that the trigger registration is rejected with
`trigger_registration_failed` (and nothing is stored), and ensure the text
references the WorkerTriggerConfig primitive exactly as defined in the docs so
SDK consumers see the correct contract.

Comment on lines +41 to +42
"function_id": "worker::add", // dotted op id
"description": "Install a worker from registry name or OCI ref", // one-line description matching the op's how-to title
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.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Terminology mismatch: worker::add is not a “dotted” id.

The example value is correct (worker::add), but the inline description should say ::-separated function id to match engine naming conventions.

As per coding guidelines: "Use :: separator for function IDs: orders::validate, reports::daily-summary".

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@new_skills/worker/skills/worker/schema.md` around lines 41 - 42, The inline
comment for the "function_id" example incorrectly calls "worker::add" a "dotted
op id"; update the comment to reference the engine convention and say something
like "::-separated function id" or "`::`-separated function id" so the example
matches naming guidance (e.g., refer to "worker::add" and the :: separator in
the comment near the "function_id" field).

@sergiofilhowz sergiofilhowz merged commit 11bacb7 into main May 25, 2026
35 checks passed
@sergiofilhowz sergiofilhowz deleted the feat/skills branch May 25, 2026 16:27
Sign up for free to 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