diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json new file mode 100644 index 0000000..f195a3e --- /dev/null +++ b/.claude-plugin/marketplace.json @@ -0,0 +1,15 @@ +{ + "name": "temporal-marketplace", + "metadata": { + "description": "A marketplace of Claude Code plugins for working with Temporal (temporal.io)" + }, + "owner": { + "name": "Temporal" + }, + "plugins": [ + { + "name": "temporal-developer", + "source": "./plugins/temporal-developer" + } + ] +} \ No newline at end of file diff --git a/.claude/settings.json b/.claude/settings.json new file mode 100644 index 0000000..28d099a --- /dev/null +++ b/.claude/settings.json @@ -0,0 +1,5 @@ +{ + "enabledPlugins": { + "plugin-dev@claude-plugins-official": true + } +} diff --git a/.claude/skills/edit-plugin-skills/SKILL.md b/.claude/skills/edit-plugin-skills/SKILL.md new file mode 100644 index 0000000..e85a1fc --- /dev/null +++ b/.claude/skills/edit-plugin-skills/SKILL.md @@ -0,0 +1,135 @@ +--- +name: edit-plugin-skills +description: This skill should be used when the user asks to "edit a skill", "update reference files", "fix a reference", "check alignment", "check correctness", "verify code examples", "update tracking", "add a new language", "edit plugin content", "modify skill references", "resume correctness verification", "check tracking status", "memory files", "run alignment checks", or mentions working on files inside plugins/ or .memory/ directories. +version: 0.1.0 +--- + +# Editing Plugin Skills + +## Overview + +This repository contains plugin skills with reference files organized by topic and language. Edits to these files must be tracked through two systems: **alignment checking** (structure and style) and **correctness checking** (factual accuracy). The tracking/memory documents in `.memory/` serve as shared state between sessions and agents. + +## Repository Structure + +``` +plugins//skills// +├── SKILL.md +└── references/ + ├── core/ # Conceptual content (language-agnostic) + ├── python/ # Python-specific code and guidance + ├── typescript/ # TypeScript-specific code and guidance + └── go/ # Go-specific (future) + +.memory/ +├── alignment_checking/ # Structure and style tracking +│ ├── README.md +│ └── .md # One file per reference topic +└── correctness_checking/ # Factual accuracy tracking + ├── README.md + └── .md # One file per reference topic +``` + +**Key principle:** Concepts belong in `core/`, language-specific code belongs in language directories. Avoid duplicating conceptual content across languages. + +## Workflow: Editing Reference Files + +### Step 1: Identify What to Edit + +Determine the scope of the change: +- Which reference file(s) to modify +- Whether the change affects structure, content, or both +- Which languages are impacted + +### Step 2: Read Current Memory State + +Before making edits, read the relevant memory files to understand current state: +- `.memory/alignment_checking/.md` for structure/style status +- `.memory/correctness_checking/.md` for verification status + +For alignment work, also read `.memory/alignment_checking/README.md` for the style target and legends. For correctness work, read `.memory/correctness_checking/README.md` for the verification workflow and status values. + +See `references/memory-formats.md` for detailed table formats and field descriptions. + +### Step 3: Make the Edit + +Edit the reference file(s) in `plugins/`. Complete all changes before updating memory. + +### Step 4: Update Memory Documents + +After completing edits, update the relevant memory documents. Refer to the protocol table below. + +| Situation | Update | +|-----------|--------| +| Reorganizing sections between files | alignment_checking/ | +| Removing duplicate conceptual content | alignment_checking/ | +| Adjusting prose style (code-first, minimal prose) | alignment_checking/ | +| Adding a new language (e.g., Go) | Both directories | +| Fixing incorrect code example | correctness_checking/ | +| Receiving SDK team feedback | correctness_checking/ | +| Verifying content against official docs | correctness_checking/ | +| Adding new reference content | Both directories | + +### Step 5: Verify No Staleness + +Memory docs must reflect **current state**, not pending work. + +**Do:** +- Complete the work first, then update the memory doc +- Update inventory tables directly (change `✓` to `—` when removing a section) +- Summarize completed changes in the Style Alignment section + +**Do not:** +- Leave `Sections marked DEL:` or `Sections marked TODO:` lists +- Leave `Action items:` lists with checkboxes +- Leave any list of "things to do" that persists after completion + +**Correct example:** +```markdown +**Style alignment:** ✅ Complete. Removed OpenTelemetry (too detailed). +``` + +**Incorrect example:** +```markdown +**Action items:** ✅ All completed +- ✅ Removed OpenTelemetry section +``` + +## Correctness Verification Workflow + +When verifying factual accuracy of code examples and statements: + +1. Read the section from the reference file +2. Query documentation sources using MCP tools (see `references/memory-formats.md` for tool names and library IDs) +3. Compare code examples against official docs +4. Apply fixes to source file if needed +5. Update memory table: Status, Fix Applied, Sources columns +6. Update Detailed Notes with verification details + +See `references/memory-formats.md` for status values and detailed table format. + +**To resume correctness work:** Check the summary table in `.memory/correctness_checking/README.md`, then find the first `unchecked` or `needs fixes` section. + +## Alignment Checking + +**Style target:** Python is the reference style (code-first, minimal prose). All languages should match. + +When checking or adjusting alignment: +1. Read the Section Inventory table in `.memory/alignment_checking/.md` +2. Verify sections exist where expected (`✓`), are intentionally missing (`—`), or need review +3. Check section ordering numbers (`Py#` / `TS#` / `Go#`) increase monotonically +4. Review Style Compliance status per language + +See `references/memory-formats.md` for the complete legend and table format. + +## Adding a New Language + +When adding a new language (e.g., Go): +1. Create `references//` directory with language-specific files +2. Update alignment memory: add column to Section Inventory tables in each `.memory/alignment_checking/.md` +3. Update correctness memory: add `## {Language}` section to each `.memory/correctness_checking/.md` +4. Update summary tables in both README files + +## References + +- **`references/memory-formats.md`** — Detailed format specifications for alignment and correctness memory tables diff --git a/.claude/skills/edit-plugin-skills/references/memory-formats.md b/.claude/skills/edit-plugin-skills/references/memory-formats.md new file mode 100644 index 0000000..ce03c6f --- /dev/null +++ b/.claude/skills/edit-plugin-skills/references/memory-formats.md @@ -0,0 +1,110 @@ +# Tracking/Memory Document Formats + +Detailed format specifications for the two memory/tracking systems used in this repository. + +## Alignment Checking + +**Location:** `.memory/alignment_checking/` + +Each file tracks one reference topic (e.g., `patterns.md` tracks all `references/*/patterns.md` files). + +### Section Inventory Table + +```markdown +| Section | Core | Python | Py# | TypeScript | TS# | Go | Go# | +|---------|------|--------|-----|------------|-----|-----|-----| +| Signals | ✓ | ✓ | 1 | ✓ | 1 | | | +| Dynamic Handlers | — | ✓ | 2 | ✓ | 2 | | | +``` + +**Column meanings:** +- `Core` / `Python` / `TypeScript` / `Go` — presence: `✓` = present, `—` = intentionally missing, empty = needs review, `TODO` = should add, `DEL` = should remove +- `Py#` / `TS#` / `Go#` — section order number (should monotonically increase if aligned with reference) + +### Style Compliance Table + +```markdown +| Language | Status | Notes | +|----------|--------|-------| +| Python | ✓ reference | Defines the target style | +| TypeScript | ✓ aligned | Matches reference | +| Go | — | Not started | +``` + +**Status values:** `✓ reference`, `✓ aligned`, `⚠️ needs work`, `—` (not started) + +### Status Section + +Document three things: +1. **Sections needing review** — empty cells, with explanation +2. **Intentionally missing** — why certain `—` entries exist +3. **Order alignment** — whether language order numbers increase monotonically +4. **Style alignment** — summary of completed style work (not TODO lists) + +--- + +## Correctness Checking + +**Location:** `.memory/correctness_checking/` + +Each file tracks one reference topic, organized by language sections (`## TypeScript`, `## Python`). + +### Tracking Table + +```markdown +| # | Section | Status | Fix Applied | Sources | +|---|---------|--------|-------------|---------| +| 1 | Signals | all good | | context7 sdk-typescript | +| 2 | Dynamic Handlers | FIXED | Used setDefaultSignalHandler | context7 sdk-typescript | +| 3 | Queries | needs fixes | | context7 sdk-typescript | +``` + +**Status values:** +- `unchecked` — not yet verified +- `all good` — verified correct, no changes needed +- `needs fixes` — issues found but not yet corrected +- `FIXED` — issues found and corrected + +**Fix Applied:** Brief description of what was changed (empty if no fix needed) + +**Sources:** Which documentation sources were consulted (e.g., `context7 sdk-typescript`, `temporal-docs`, `SDK team feedback`) + +### Detailed Notes + +Below each tracking table, include a subsection per row with: + +```markdown +#### 1. Section Name +**Status:** all good | needs fixes | FIXED + +**Verified:** (for all good) +- Specific fact checked ✓ + +**Issues:** (for needs fixes / FIXED) +- Description of the problem +- What the correct behavior should be + +**Before/After:** (for FIXED, include code snippets) + +**Source:** URL or reference +``` + +### Verification Sources + +Use these MCP tools for verification: +- `mcp__context7__query-docs` — SDK-specific code verification (use with library IDs like `/temporalio/sdk-typescript` or `/temporalio/sdk-python`) +- `mcp__temporal-docs__search_temporal_knowledge_sources` — conceptual verification against Temporal documentation + +### Summary Table (README.md) + +The `.memory/correctness_checking/README.md` contains a summary table: + +```markdown +| File | TypeScript | Python | Go | +|------|------------|--------|-----| +| patterns.md | ✅ | partial | — | +``` + +**Legend:** `✅` = all sections verified, `partial` = some sections need fixes/unchecked, `unchecked` = not yet verified, `—` = N/A + +Update this table whenever a file's overall status changes. diff --git a/.claude/skills/translate-skill-to/SKILL.md b/.claude/skills/translate-skill-to/SKILL.md new file mode 100644 index 0000000..01d997d --- /dev/null +++ b/.claude/skills/translate-skill-to/SKILL.md @@ -0,0 +1,41 @@ +--- +name: translate-skill-to +description: Translates the skill to another language +disable-model-invocation: true +--- + +The skill at @plugins/temporal-developer/skills/temporal-developer/ currently supports Python and TypeScript. Your task is to add +support for $ARGUMENTS. + +First, make sure that we are working off of a fresh branch for both this repo and the git submodule at plugins/temporal-developer/skills/temporal-developer. The branch should be branched from `dev`. If the user is already on a feature branch or has non-clean Git state, communicate with the user, DON'T just nuke their git state. + +You will then add support for $ARGUMENTS in phases: + +1) Create/update alignment docs for the $ARGUMENTS content, to determine * what is appropriate for $ARGUMENTS *. Many things in core/python/typescript + will be directly relevant for $ARGUMENTS. But somethings might not be (sandboxing, etc.). You must determine these case-by-case, using the + temporal docs mcp server. Expected output of this step: updated/new alignment memory docs. Do not yet write actual content / code + examples. Make sure not to remove/overwrite all the existing notes (Python, TypeScript, etc.) as those are important to keep. Once approved, commit it. + +2) Create all the code examples for $ARGUMENTS, that are specified in the alignment memory docs you just wrote. They should follow + stylistic guidelines that generally match the Python and TypeScript content, but obviously should be appropriate for $ARGUMENTS. You should likely use the temporal docs MCP server to lookup code samples. This step is potentially massively parallizable. When done, commit it. + +3) Do a detailed self-review pass for *alignment* level issues for $ARGUMENTS, compared to Python/TypeScript. Don't yet worry about correctness, just presence/lack of content, and more/less verbosity. Mistakes you likely made: a) Python had a section who's content is merely just "See ... for more info". In $ARGUMENTS you incorrectly filled that out with full content. b) Missing section/subsections. c) Slightly differently named sections for no reason. As you work through this self-review, you may find that the alignment memory docs were unclear/ambiguous. If that is the case, update them for clarity. When all done, commit this. + +4) Do a correctness checking pass, to look for issues. Do not yet fix any issues, just identify them and update the correctness + memory doc with reserach on what the appropriate fix is. This step is potentially massively parallizable. Make sure not to remove/overwrite all the existing notes (Python, TypeScript, etc.) as those are important to keep. Ask for review from user about all correctness issues and your ideas for fixes. When approved, commit this. + +5) Apply the correctness edits to the actual content files. This step is potentially massively parallizable. When done, commit this. + +6) Update all files that reference supported languages to include $ARGUMENTS: + - `SKILL.md` frontmatter `description` field: add trigger phrases like "Temporal $ARGUMENTS" + - `SKILL.md` Overview: update the list of supported languages + - `SKILL.md` Getting Started > Read All Relevant References: add entry for $ARGUMENTS + - `references/core/determinism.md` SDK Protection Mechanisms: add $ARGUMENTS entry describing its determinism enforcement approach + - Any other `core/` files that enumerate languages explicitly + When done, commit this. + +Do these steps one at a time, asking for human review after each step. + +Make sure to use the /edit-plugin-skills skill to have an understanding of how to work with the alignment and correctness memory docs. + +As a general rule, prefer the temporal-docs server over context7, as it is generally more accurate. Use context7 to fill in information you can't otherwise get. diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 0000000..872c89b --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1 @@ +* @temporalio/ai-sdk diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..0c551e0 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "plugins/temporal-developer/skills/temporal-developer"] + path = plugins/temporal-developer/skills/temporal-developer + url = https://github.com/temporalio/skill-temporal-developer diff --git a/.memory/alignment_checking/README.md b/.memory/alignment_checking/README.md new file mode 100644 index 0000000..716d627 --- /dev/null +++ b/.memory/alignment_checking/README.md @@ -0,0 +1,47 @@ +# Alignment Checking + +Track content alignment (do files have the right sections?) and style alignment (is prose level appropriate?) across reference files for the **temporal-developer** skill. + +**Skill location:** `plugins/temporal-developer/skills/temporal-developer/` +**Reference files:** `plugins/temporal-developer/skills/temporal-developer/references/` + +## Style Target + +Python is the reference style (code-first, minimal prose). All languages should match. + +**Style compliance legend:** +- `✓ reference` = defines the target style +- `✓ aligned` = matches reference style +- `⚠️ needs work` = has style issues to address +- `—` = not started + +## Section Inventory Legend + +- `✓` = present +- ` ` (empty) = missing, unknown if intentional (needs review) +- `—` = missing, intentional (language doesn't need this) +- `TODO` = missing, should add +- `DEL` = present, should remove or merge +- `Py#` / `TS#` / `Go#` = section order in file (should monotonically increase if order is aligned) + +## Implementation Status + +**Python/TypeScript:** ✅ COMPLETE (2026-02-25) — All TODO/DEL/BUG items implemented. + +**Go:** ✅ COMPLETE (2026-03-17) — All Go reference files created and aligned. + +## Files + +Each file in this directory tracks alignment for a corresponding reference file: + +- [patterns.md](./patterns.md) +- [data-handling.md](./data-handling.md) +- [error-handling.md](./error-handling.md) +- [gotchas.md](./gotchas.md) +- [observability.md](./observability.md) +- [testing.md](./testing.md) +- [versioning.md](./versioning.md) +- [language.md](./language.md) — top-level `{language}.md` files (python.md, typescript.md, etc.) +- [determinism-protection.md](./determinism-protection.md) +- [determinism.md](./determinism.md) +- [advanced-features.md](./advanced-features.md) diff --git a/.memory/alignment_checking/advanced-features.md b/.memory/alignment_checking/advanced-features.md new file mode 100644 index 0000000..b82ae08 --- /dev/null +++ b/.memory/alignment_checking/advanced-features.md @@ -0,0 +1,49 @@ +# advanced-features.md + +## Section Inventory + +| Section | Core | Python | Py# | TypeScript | TS# | Go | +|---------|------|--------|-----|------------|-----|-----| +| Schedules | — | ✓ | 1 | ✓ | 1 | | +| Async Activity Completion | — | ✓ | 2 | ✓ | 2 | | +| Sandbox Customization | — | ✓ | 3 | — | — | | +| Gevent Compatibility Warning | — | ✓ | 4 | — | — | | +| Worker Tuning | — | ✓ | 5 | ✓ | 3 | | +| Workflow Init Decorator | — | ✓ | 6 | — | — | | +| Workflow Failure Exception Types | — | ✓ | 7 | — | — | | +| Continue-as-New | — | — | — | — | — | | +| Workflow Updates | — | — | — | — | — | | +| Nexus Operations | — | — | — | — | — | | +| Activity Cancellation and Heartbeating | — | — | — | — | — | | +| Sinks | — | — | — | ✓ | 4 | | +| CancellationScope Patterns | — | — | — | — | — | | +| Best Practices | — | — | — | — | — | | + +## Style Compliance + +| Language | Status | Notes | +|----------|--------|-------| +| Python | ✓ reference | 7 sections | +| TypeScript | ✓ aligned | 4 sections (removed duplicates) | +| Go | ✓ aligned | 4 sections — Schedules, Async Completion, Worker Tuning, Sessions | + +## Status + +**Go-specific notes:** +- Schedules: `client.ScheduleClient` — same concept as Python/TS +- Async Activity Completion: `activity.GetInfo(ctx).TaskToken` + `client.CompleteActivity` / `client.CompleteActivityByID` +- Worker Tuning: `worker.Options` — `MaxConcurrentActivityExecutionSize`, `MaxConcurrentWorkflowTaskExecutionSize`, `MaxConcurrentActivityTaskPollers` +- Sessions: Go-specific feature — `workflow.CreateSession(ctx, options)` pins activities to a specific worker. Useful for file processing where activities need local state. +**Intentionally missing (`—`):** +- Core column: advanced features are implementation-specific +- Sandbox Customization: Python-specific; Go has no sandbox +- Gevent Compatibility Warning: Python-specific +- Workflow Init Decorator: Python-specific +- Workflow Failure Exception Types: Python-specific +- Sinks: TS-specific feature +- Sessions: Go-specific (not in Python/TS) +- Interceptors: Decided not to include for any language (all SDKs have them, but too advanced for current scope) + +**Order alignment:** N/A — Files have different structures by design + +**Style alignment:** ✅ Complete (Python, TypeScript, Go) diff --git a/.memory/alignment_checking/data-handling.md b/.memory/alignment_checking/data-handling.md new file mode 100644 index 0000000..1f1bbc1 --- /dev/null +++ b/.memory/alignment_checking/data-handling.md @@ -0,0 +1,48 @@ +# data-handling.md + +## Section Inventory + +| Section | Core | Python | Py# | TypeScript | TS# | Go | Go# | +|---------|------|--------|-----|------------|-----|-----|-----| +| Overview | — | ✓ | 1 | ✓ | 1 | ✓ | 1 | +| Default Data Converter | — | ✓ | 2 | ✓ | 2 | ✓ | 2 | +| Pydantic Integration | — | ✓ | 3 | — | — | — | — | +| Custom Data Converter | — | ✓ | 4 | ✓ | 3 | ✓ | 3 | +| Composition of Payload Converters | — | — | — | ✓ | 4 | ✓ | 4 | +| Protobuf Support | — | — | — | ✓ | 5 | ✓ | 5 | +| Payload Encryption | — | ✓ | 5 | ✓ | 6 | ✓ | 6 | +| Search Attributes | — | ✓ | 6 | ✓ | 7 | ✓ | 7 | +| Workflow Memo | — | ✓ | 7 | ✓ | 8 | ✓ | 8 | +| Large Payloads | — | — | — | — | — | — | — | +| Deterministic APIs for Values | — | ✓ | 8 | — | — | — | — | +| Best Practices | — | ✓ | 9 | ✓ | 9 | ✓ | 9 | + +## Style Compliance + +| Language | Status | Notes | +|----------|--------|-------| +| Python | ✓ reference | — | +| TypeScript | ✓ aligned | — | +| Go | ✓ aligned | JSON default, protobuf native, converter.CompositeDataConverter | + +## Status + +**Go-specific notes:** +- Default Data Converter: Go uses `converter.NewCompositeDataConverter()` with JSON as default — chain: NilPayloadConverter, ByteSlicePayloadConverter, ProtoPayloadConverter, ProtoJSONPayloadConverter, JSONPayloadConverter +- Custom Data Converter: implement `converter.DataConverter` interface +- Composition of Payload Converters: Go has `converter.NewCompositeDataConverter()` — similar to TS +- Protobuf Support: Go has native proto support via `converter.NewProtoPayloadConverter()` — both proto binary and proto JSON +- Payload Encryption: Go uses `converter.PayloadCodec` interface for encryption/compression +- Search Attributes: `workflow.UpsertSearchAttributes(ctx, map)`, query via client +- Workflow Memo: set in `client.StartWorkflowOptions` +- Note on v1.26.0+: proto types changed from gogo to google protobuf; `LegacyTemporalProtoCompat` option available + +**Intentionally missing (`—`):** +- Core column: data handling is implementation-specific +- Pydantic Integration: Python-specific +- Deterministic APIs for Values: Python-specific; Go covers in determinism.md Safe Builtin Alternatives +- Large Payloads: Moved to core/patterns.md and core/gotchas.md + +**Order alignment:** ✅ ALIGNED — Go sections follow same order as Python/TypeScript + +**Style alignment:** ✅ Complete (Python, TypeScript, Go) diff --git a/.memory/alignment_checking/determinism-protection.md b/.memory/alignment_checking/determinism-protection.md new file mode 100644 index 0000000..c0ef0f0 --- /dev/null +++ b/.memory/alignment_checking/determinism-protection.md @@ -0,0 +1,54 @@ +# determinism-protection.md + +## Section Inventory + +| Section | Core | Python | Py# | TypeScript | TS# | Go | Go# | +|---------|------|--------|-----|------------|-----|-----|-----| +| Overview | — | ✓ | 1 | ✓ | 1 | ✓ | 1 | +| How the Sandbox Works | — | ✓ | 2 | — | — | — | — | +| Import Blocking | — | — | — | ✓ | 2 | — | — | +| Forbidden Operations | — | ✓ | 3 | — | — | — | — | +| Function Replacement | — | — | — | ✓ | 3 | — | — | +| workflowcheck Static Analysis | — | — | — | — | — | ✓ | 2 | +| Determinism Rules | — | — | — | — | — | ✓ | 3 | +| Pass-Through Pattern | — | ✓ | 4 | — | — | — | — | +| Importing Activities | — | ✓ | 5 | — | — | — | — | +| Disabling the Sandbox | — | ✓ | 6 | — | — | — | — | +| Customizing Invalid Module Members | — | ✓ | 7 | — | — | — | — | +| Import Notification Policy | — | ✓ | 8 | — | — | — | — | +| Disable Lazy sys.modules Passthrough | — | ✓ | 9 | — | — | — | — | +| File Organization | — | ✓ | 10 | — | — | — | — | +| Common Issues | — | ✓ | 11 | — | — | — | — | +| Best Practices | — | ✓ | 12 | — | — | ✓ | 4 | + +## Style Compliance + +| Language | Status | Notes | +|----------|--------|-------| +| Python | ✓ reference | Comprehensive (12 sections) | +| TypeScript | ✓ aligned | Minimal (3 sections) — V8 is automatic | +| Go | ✓ aligned | Minimal (4 sections) — no runtime sandbox, convention + static analysis | + +## Status + +**Go-specific notes:** +- Go has NO runtime sandbox (unlike Python's import-restricting sandbox or TS's V8 isolate) +- Determinism enforcement is purely by developer convention + optional static analysis +- `workflowcheck` tool: `go.temporal.io/sdk/contrib/tools/workflowcheck` — detects non-deterministic function calls, channel ops, goroutines, map range +- The tool flags: `time.Now`, `time.Sleep`, `math/rand.globalRand`, `crypto/rand.Reader`, `os.Stdin/Stdout/Stderr`, native goroutines, channel send/receive/range, map range iteration +- Determinism Rules section: covers what developers must avoid (unique to Go since no sandbox catches these) +- Overview: brief explanation that Go relies on convention rather than sandboxing +- Best Practices: use workflowcheck in CI, follow workflow.* API conventions + +**Intentionally missing (`—`):** +- Core column: no core file (sandbox implementation is language-specific) +- Most Python sections (sandbox internals, import blocking, pass-through, customization): Not applicable to Go (no sandbox) +- TS sections (Import Blocking, Function Replacement): Not applicable to Go (no V8 isolate) +- Go doesn't need sandbox customization sections because there's no sandbox to customize + +**Order alignment:** N/A — files have completely different structures per language + +**Style alignment:** ⚠️ Very different structures (intentional, different protection mechanisms) +- Python: Comprehensive (12 sections) — complex sandbox with many customization options +- TypeScript: Minimal (3 sections) — V8 sandbox is mostly automatic +- Go: Minimal (4 sections) — no sandbox, convention-based with static analysis tool diff --git a/.memory/alignment_checking/determinism.md b/.memory/alignment_checking/determinism.md new file mode 100644 index 0000000..5419d4d --- /dev/null +++ b/.memory/alignment_checking/determinism.md @@ -0,0 +1,54 @@ +# determinism.md + +## Section Inventory + +| Section | Core | Core# | Python | Py# | TypeScript | TS# | Go | Go# | +|---------|------|-------|--------|-----|------------|-----|-----|-----| +| Overview | ✓ | 1 | ✓ | 1 | ✓ | 1 | ✓ | 1 | +| Why Determinism Matters | ✓ | 2 | ✓ | 2 | ✓ | 2 | ✓ | 2 | +| Sources of Non-Determinism | ✓ | 3 | — | — | — | — | — | — | +| Central Concept: Activities | ✓ | 4 | — | — | — | — | — | — | +| SDK Protection / Sandbox | ✓ | 5 | ✓ | 6 | ✓ | 3 | — | — | +| Forbidden Operations | — | — | ✓ | 3 | ✓ | 4 | ✓ | 3 | +| Safe Builtin Alternatives | — | — | ✓ | 4 | — | — | ✓ | 4 | +| Detecting Non-Determinism | ✓ | 6 | — | — | — | — | — | — | +| Recovery from Non-Determinism | ✓ | 7 | — | — | — | — | — | — | +| Testing Replay Compatibility | — | — | ✓ | 5 | ✓ | 5 | ✓ | 5 | +| Best Practices | ✓ | 8 | ✓ | 7 | ✓ | 6 | ✓ | 6 | + +## Style Compliance + +| Language | Status | Notes | +|----------|--------|-------| +| Core | ✓ reference | Deep conceptual content | +| Python | ✓ aligned | Practical focus | +| TypeScript | ✓ aligned | Practical focus, V8 sandbox | +| Go | ✓ aligned | Practical focus, no sandbox, workflowcheck tool, workflow.* replacements | + +## Status + +**Go-specific notes:** +- SDK Protection: Go merged this into Overview (cross-references `determinism-protection.md` instead of having separate section). Marked `—` in table. +- Testing Replay: Go cross-references `testing.md` rather than inlining code (matching Python style) +- Forbidden Operations: Go-specific list — native goroutines, native channels, native select, map range iteration, time.Now/Sleep, crypto/rand, os.Stdin/Stdout/Stderr, anonymous functions as local activities (non-deterministic name) +- Safe Builtin Alternatives: Go has a table similar to Python — `workflow.Go()` for goroutines, `workflow.Channel` for channels, `workflow.Selector` for select, `workflow.Now()` for time, `workflow.SideEffect` for random, `workflow.Sleep` for sleep +- Testing Replay: Go uses `worker.ReplayWorkflowHistory` from testsuite +- `workflowcheck` tool: static analysis that detects non-deterministic function calls at compile time (runs as linter) + +**Intentionally missing (`—`):** +- Sources of Non-Determinism: Core-only (conceptual categories) +- Central Concept: Activities: Core-only (conceptual) +- Forbidden Operations: Language-specific (Core covers in Sources) +- Safe Builtin Alternatives: Python and Go have tables, TS doesn't need (V8 sandbox handles automatically) +- Detecting Non-Determinism: Core-only +- Recovery from Non-Determinism: Core-only +- Testing Replay Compatibility: Language-specific (Core covers in Detecting) + +**Order alignment:** N/A — different structures by design + +**Style alignment:** ✓ Well aligned (Python, TypeScript) +- Core: Deep conceptual content (replay mechanism, commands/events, recovery) +- Python: Practical focus (forbidden operations, safe alternatives table, sandbox) +- TypeScript: Practical focus (V8 sandbox, forbidden operations) +- Go follows Python pattern: forbidden operations + safe alternatives table + workflowcheck +- Good division: Core explains "why", languages explain "how" diff --git a/.memory/alignment_checking/error-handling.md b/.memory/alignment_checking/error-handling.md new file mode 100644 index 0000000..6f9d2c8 --- /dev/null +++ b/.memory/alignment_checking/error-handling.md @@ -0,0 +1,44 @@ +# error-handling.md + +## Section Inventory + +| Section | Core | Python | Py# | TypeScript | TS# | Go | Go# | +|---------|------|--------|-----|------------|-----|-----|-----| +| Overview | — | ✓ | 1 | ✓ | 1 | ✓ | 1 | +| Application Errors/Failures | — | ✓ | 2 | ✓ | 2 | ✓ | 2 | +| Non-Retryable Errors | — | ✓ | 3 | — | — | ✓ | 3 | +| Activity Errors | — | — | — | ✓ | 3 | — | — | +| Handling Activity Errors in Workflows | — | ✓ | 4 | ✓ | 4 | ✓ | 4 | +| Retry Configuration | — | ✓ | 5 | ✓ | 5 | ✓ | 5 | +| Timeout Configuration | — | ✓ | 6 | ✓ | 6 | ✓ | 6 | +| Workflow Failure | — | ✓ | 7 | ✓ | 7 | ✓ | 7 | +| Cancellation Handling in Activities | — | — | — | — | — | — | — | +| Idempotency Patterns | — | — | — | ✓ | 8 | — | — | +| Best Practices | — | ✓ | 8 | ✓ | 9 | ✓ | 8 | + +## Style Compliance + +| Language | Status | Notes | +|----------|--------|-------| +| Python | ✓ reference | — | +| TypeScript | ✓ aligned | Uses `log`, has retry defaults note | +| Go | ✓ aligned | Go-style error handling (errors.As, error returns, no exceptions) | + +## Status + +**Go-specific notes:** +- Go uses error returns (not exceptions) — `if err != nil` pattern +- Application Errors: `temporal.NewApplicationError("msg", "type", details...)` and `temporal.NewNonRetryableApplicationError("msg", "type", cause, details...)` +- Non-Retryable: Go has both `temporal.NewNonRetryableApplicationError()` and `NonRetryableErrorTypes` in RetryPolicy +- Handling Activity Errors: `errors.As(err, &applicationErr)` pattern — check `*temporal.ApplicationError`, `*temporal.TimeoutError`, `*temporal.CanceledError`, `*temporal.PanicError` +- Retry Config: `temporal.RetryPolicy` struct with `InitialInterval`, `BackoffCoefficient`, `MaximumInterval`, `MaximumAttempts`, `NonRetryableErrorTypes` +- Timeout Config: `workflow.ActivityOptions` with `StartToCloseTimeout`, `ScheduleToCloseTimeout`, etc. +- Workflow Failure: returning any error from a workflow function fails the workflow + +**Intentionally missing (`—`):** +- Core column: error handling is implementation-specific +- Activity Errors: TS-specific section (Go covers in Handling Activity Errors) + +**Order alignment:** ✓ Aligned — Go# monotonically increases + +**Style alignment:** ✅ Complete (Python, TypeScript, Go) diff --git a/.memory/alignment_checking/gotchas.md b/.memory/alignment_checking/gotchas.md new file mode 100644 index 0000000..9246722 --- /dev/null +++ b/.memory/alignment_checking/gotchas.md @@ -0,0 +1,63 @@ +# gotchas.md + +## Section Inventory + +| Section | Core | Core# | Python | Py# | TypeScript | TS# | Go | Go# | +|---------|------|-------|--------|-----|------------|-----|-----|-----| +| Idempotency / Non-Idempotent Activities | ✓ | 1 | — | — | — | — | — | — | +| Replay Safety / Side Effects & Non-Determinism | ✓ | 2 | — | — | — | — | — | — | +| Multiple Workers with Different Code | ✓ | 3 | — | — | — | — | — | — | +| Retry Policies / Failing Activities Too Quickly | ✓ | 4 | — | — | — | — | — | — | +| Query Handler & Update Validator Mistakes | ✓ | 5 | — | — | — | — | — | — | +| File Organization | ✓ | 6 | ✓ | 1 | — | — | — | — | +| Activity Imports | — | — | — | — | ✓ | 1 | — | — | +| Bundling Issues | — | — | — | — | ✓ | 2 | — | — | +| Async vs Sync Activities | — | — | ✓ | 2 | — | — | — | — | +| Goroutines and Concurrency | — | — | — | — | — | — | ✓ | 1 | +| Non-Deterministic Operations | — | — | — | — | — | — | ✓ | 2 | +| Error Handling | ✓ | 8 | — | — | — | — | — | — | +| Wrong Retry Classification | ✓ | 8 | ✓ | 3 | ✓ | 3 | ✓ | 3 | +| Heartbeating | — | — | ✓ | 4 | ✓ | 5 | ✓ | 4 | +| Cancellation | ✓ | 9 | ✓ | 5 | ✓ | 4 | ✓ | 5 | +| Testing | ✓ | 7 | ✓ | 6 | ✓ | 6 | ✓ | 6 | +| Timers and Sleep | — | — | ✓ | 7 | ✓ | 7 | ✓ | 7 | +| Payload Size Limits | ✓ | 10 | — | — | — | — | — | — | + +## Style Compliance + +| Language | Status | Notes | +|----------|--------|-------| +| Core | ✓ reference | Conceptual gotchas | +| Python | ✓ aligned | Language-specific gotchas | +| TypeScript | ✓ aligned | Language-specific gotchas | +| Go | ✓ aligned | Language-specific gotchas — goroutines, channels, selectors, map range | + +## Status + +**Go-specific notes:** +- Goroutines and Concurrency: MUST use `workflow.Go()` not native `go`, `workflow.Channel` not native channels, `workflow.Selector` not native `select` +- Non-Deterministic Operations: map range iteration, `time.Now()`/`time.Sleep()`, `math/rand`, accessing `os.Stdin`/`os.Stdout`/`os.Stderr`, anonymous functions as local activities (non-deterministic name — use named functions instead) +- Wrong Retry Classification: cross-references `error-handling.md` (no inline code, matching Python style) +- Heartbeating: moved before Cancellation (Go# 4) to match conceptual flow — heartbeating is prerequisite for activity cancellation +- Cancellation: Go uses `ctx.Done()` channel + `workflow.NewDisconnectedContext` for cleanup +- Testing: common mistakes with Go test framework (forgetting to register activities, using `time.Sleep` in tests) +- Timers: using `time.Sleep` instead of `workflow.Sleep`; using `time.After` instead of `workflow.NewTimer` + +**Decided to keep as-is:** +- Multiple Workers with Different Code: Core-only (conceptual explanation sufficient) +- Heartbeating: Py/TS/Go-only (language-specific code examples, no Core conceptual section needed) + +**Intentionally missing (`—`):** +- Idempotency, Replay Safety, Query Handlers, Error Handling, Retry Policies, Payload Size Limits: Core-only (conceptual) +- Multiple Workers with Different Code: Core-only (conceptual) +- File Organization: Core + Python; TS covers similar in Activity Imports; Go has simpler package model +- Activity Imports: TS-specific (bundling/sandbox concerns) +- Bundling Issues: TS-specific (workflow bundling) +- Async vs Sync Activities: Python-specific + +**Order alignment:** N/A — Core has conceptual sections, language files have implementation-specific sections + +**Style alignment:** ✅ Complete (Python, TypeScript, Go) +- Core: 10 conceptual sections with symptoms/fixes +- TypeScript: 7 sections (Activity Imports, Bundling, Cancellation, Heartbeating, Testing, Timers, Wrong Retry Classification) +- Python: 7 sections (File Organization, Async vs Sync, Wrong Retry Classification, Cancellation, Heartbeating, Testing, Timers and Sleep) diff --git a/.memory/alignment_checking/language.md b/.memory/alignment_checking/language.md new file mode 100644 index 0000000..2b996ed --- /dev/null +++ b/.memory/alignment_checking/language.md @@ -0,0 +1,53 @@ +# {language}.md (top-level files) + +Tracks alignment for `python.md`, `typescript.md`, `go.md`, etc. + +## Section Inventory + +| Section | Core | Python | Py# | TypeScript | TS# | Go | Go# | +|---------|------|--------|-----|------------|-----|-----|-----| +| Overview | — | ✓ | 1 | ✓ | 1 | ✓ | 1 | +| How Temporal Works: History Replay | — | — | — | — | — | — | — | +| Understanding Replay | — | — | — | ✓ | 2 | — | — | +| Quick Start / Quick Demo | — | ✓ | 2 | ✓ | 3 | ✓ | 2 | +| Key Concepts | — | ✓ | 3 | ✓ | 4 | ✓ | 3 | +| File Organization Best Practice | — | ✓ | 4 | ✓ | 5 | ✓ | 4 | +| Determinism Rules | — | — | — | ✓ | 6 | — | — | +| Common Pitfalls | — | ✓ | 5 | ✓ | 7 | ✓ | 5 | +| Writing Tests | — | ✓ | 6 | ✓ | 8 | ✓ | 6 | +| Additional Resources | — | ✓ | 7 | ✓ | 9 | ✓ | 7 | + +## Style Compliance + +| Language | Status | Notes | +|----------|--------|-------| +| Python | ✓ reference | — | +| TypeScript | ✓ aligned | Has Understanding Replay, Determinism Rules | +| Go | ✓ aligned | Function-based (no decorators), workflowcheck, struct activities | + +## Status + +**Section content notes:** +- Writing Tests: all languages should be a brief link to `references//testing.md`, NOT inline code examples + +**Go-specific notes:** +- Go uses exported functions (not decorators) for workflows/activities +- Activities commonly defined as struct methods for dependency injection +- Worker setup: `worker.New(client, taskQueue, options)` + `w.RegisterWorkflow` / `w.RegisterActivity` +- Determinism rules included in Key Concepts subsection (like Python), not separate section +- Understanding Replay: TS-specific section; Go references core like Python +- `workflowcheck` static analysis tool mentioned in Key Concepts (Go-specific) +- File organization: Go uses separate packages (workflows/, activities/, worker/) + +**Intentionally missing (`—`):** +- Core column: no core top-level file (these are language entry points) +- Determinism Rules — TS has separate section; Python/Go have subsection in Key Concepts +- Understanding Replay — TS-specific; Python/Go reference core + +**Order alignment:** ✓ Aligned — All languages have similar structure (Overview, Quick Start, Key Concepts, File Organization, Common Pitfalls, Writing Tests, Additional Resources) + +**Style alignment:** ✅ Complete (Python, TypeScript, Go) +- Removed "How Temporal Works" from TS (now brief "Understanding Replay" referencing core) +- Added "File Organization Best Practice" to TS +- Python Quick Demo and TypeScript Quick Start now match (full tutorial with 4 files, run instructions, expected output) +- Both Key Concepts and Common Pitfalls sections aligned diff --git a/.memory/alignment_checking/observability.md b/.memory/alignment_checking/observability.md new file mode 100644 index 0000000..47a86fb --- /dev/null +++ b/.memory/alignment_checking/observability.md @@ -0,0 +1,40 @@ +# observability.md + +## Section Inventory + +| Section | Core | Python | Py# | TypeScript | TS# | Go | Go# | +|---------|------|--------|-----|------------|-----|-----|-----| +| Overview | — | ✓ | 1 | ✓ | 1 | ✓ | 1 | +| Logging / Replay-Aware Logging | — | ✓ | 2 | ✓ | 2 | ✓ | 2 | +| Customizing the Logger | — | ✓ | 2 | ✓ | 3 | ✓ | 3 | +| OpenTelemetry Integration | — | — | — | — | — | — | — | +| Metrics | — | ✓ | 3 | ✓ | 4 | ✓ | 4 | +| Search Attributes (Visibility) | — | ✓ | 4 | — | — | ✓ | 5 | +| Debugging with Event History | — | — | — | — | — | — | — | +| Best Practices | — | ✓ | 5 | ✓ | 5 | ✓ | 6 | + +## Style Compliance + +| Language | Status | Notes | +|----------|--------|-------| +| Python | ✓ reference | — | +| TypeScript | ✓ aligned | Removed verbose sections | +| Go | ✓ aligned | workflow.GetLogger, slog integration, Tally/Prometheus metrics | + +## Status + +**Go-specific notes:** +- Logging: `workflow.GetLogger(ctx)` for replay-safe workflow logging; `activity.GetLogger(ctx)` for activity logging +- Customizing: Go 1.21+ supports `log.NewStructuredLogger(slog.New(...))` via `client.Options.Logger`; also supports custom `log.Logger` interface +- Metrics: Go uses Tally library (`go.temporal.io/sdk/contrib/tally`) for Prometheus integration; `client.Options.MetricsHandler` +- Tracing: Go supports OpenTelemetry, OpenTracing, and Datadog via `contrib/` packages and interceptors +- Search Attributes: Go includes visibility/search attributes in observability (like Python, unlike TS) + +**Intentionally missing (`—`):** +- Core column: no core observability.md exists (implementation-specific) +- OpenTelemetry / Debugging: Removed as too detailed +- Search Attributes: Python/Go include; TS keeps in data-handling.md + +**Order alignment:** ✓ Aligned — Go# monotonically increases + +**Style alignment:** ✅ Complete (Python, TypeScript, Go) diff --git a/.memory/alignment_checking/patterns.md b/.memory/alignment_checking/patterns.md new file mode 100644 index 0000000..9485753 --- /dev/null +++ b/.memory/alignment_checking/patterns.md @@ -0,0 +1,88 @@ +# patterns.md + +## Section Inventory + +| Section | Core | Python | Py# | TypeScript | TS# | Go | Go# | +|---------|------|--------|-----|------------|-----|-----|-----| +| Signals | ✓ | ✓ | 1 | ✓ | 1 | ✓ | 1 | +| Dynamic Signal Handlers | — | ✓ | 2 | ✓ | 2 | — | — | +| Queries | ✓ | ✓ | 3 | ✓ | 3 | ✓ | 2 | +| Dynamic Query Handlers | — | ✓ | 4 | ✓ | 4 | — | — | +| Updates | ✓ | ✓ | 5 | ✓ | 5 | ✓ | 3 | +| Child Workflows | ✓ | ✓ | 6 | ✓ | 6 | ✓ | 4 | +| Child Workflow Options | — | — | — | ✓ | 7 | ✓ | 4s | +| Handles to External Workflows | — | ✓ | 7 | ✓ | 8 | ✓ | 5 | +| Parallel Execution | ✓ | ✓ | 8 | ✓ | 9 | ✓ | 6 | +| Deterministic Asyncio Alternatives | — | ✓ | 9 | — | — | — | — | +| Selector Pattern | — | — | — | — | — | ✓ | 7 | +| Continue-as-New | ✓ | ✓ | 10 | ✓ | 10 | ✓ | 8 | +| Cancellation Handling (asyncio) | — | ✓ | 12 | — | — | — | — | +| Cancellation Scopes | — | — | — | ✓ | 12 | — | — | +| Cancellation Handling | — | — | — | — | — | ✓ | 9 | +| Saga Pattern | ✓ | ✓ | 11 | ✓ | 11 | ✓ | 10 | +| Triggers | — | — | — | ✓ | 13 | — | — | +| Wait Condition with Timeout | — | ✓ | 13 | ✓ | 14 | ✓ | 11 | +| Waiting for All Handlers to Finish | — | ✓ | 14 | ✓ | 15 | ✓ | 12 | +| Activity Heartbeat Details | ✓ | ✓ | 15 | ✓ | 16 | ✓ | 13 | +| Timers | ✓ | ✓ | 16 | ✓ | 17 | ✓ | 14 | +| Large Data Handling | ✓ | — | — | — | — | — | — | +| Local Activities | ✓ | ✓ | 17 | ✓ | 18 | ✓ | 15 | +| Entity Workflow Pattern | ✓ | — | — | — | — | — | — | +| Polling Patterns | ✓ | — | — | — | — | — | — | +| Idempotency Patterns | ✓ | — | — | — | — | — | — | +| Using Pydantic Models | — | ✓ | 18 | — | — | — | — | + +## Style Compliance + +| Language | Status | Notes | +|----------|--------|-------| +| Python | ✓ reference | — | +| TypeScript | ✓ aligned | Uses `log`, CancellationScope idiom | +| Go | ✓ aligned | Channel-based signals, SetQueryHandler, SetUpdateHandler, Selector, compensation slice saga | + +## Status + +**Cross-language notes:** +- **Updates — Validator constraints:** All languages (core, Python, TS, Go) now document that validators must NOT mutate state or block (read-only, like query handlers). Added in PR #38 review. +- Cancellation Handling reordered before Saga in Go (Go# 9→10) so `NewDisconnectedContext` is introduced before Saga uses it +- Saga Pattern in Go now uses `NewDisconnectedContext` for compensations (PR #38 review) +- Local Activities: added WFT persistence risk warning to **core** (applies to all languages, not Go-specific). PR #38 review. + +**Go-specific notes:** +- Child Workflow Options: demoted to `###` subsection under Child Workflows in Go (Go# 4s = subsection of 4). TS has it as separate `##`. +- Activity Heartbeating renamed to Activity Heartbeat Details (matching Python/TS naming) + +**Go-specific notes (API details):** +- Signals use `workflow.GetSignalChannel` + `workflow.Selector` (channel-based, not handler-based) +- Dynamic Signal/Query Handlers: Go handles signals by channel name; no "default handler" concept → marked `—` +- Queries use `workflow.SetQueryHandler` (string name + function) +- Updates use `workflow.SetUpdateHandlerWithOptions` with optional `Validator` +- Parallel Execution uses `workflow.Go()` (not goroutines) + `workflow.Selector` +- Selector Pattern: Go-specific section — `workflow.Selector` replaces `select` statement (unique to Go SDK) +- Cancellation Handling: Go uses `ctx.Done()` channel + `workflow.NewDisconnectedContext` (different from Python asyncio.CancelledError and TS CancellationScope) +- Saga Pattern: Go idiom uses `defer` for compensations +- Wait Condition: Go uses `workflow.Await` / `workflow.AwaitWithTimeout` +- Continue-as-New: Go returns `workflow.NewContinueAsNewError` (error-based, not function call) +- Cancellation Scopes / Triggers / Deterministic Asyncio: Not applicable to Go → marked `—` + +**Decided to keep as Core-only:** +- Large Data Handling: Core conceptual explanation sufficient (language-agnostic pattern) +- Polling Patterns: Core conceptual explanation sufficient +- Idempotency Patterns: Core conceptual explanation sufficient + +**Intentionally missing (`—`):** +- Dynamic handlers, External workflow handles, Wait conditions: language-specific implementation, core has concepts only +- Child Workflow Options: TS-specific (Python shows inline) +- Deterministic Asyncio Alternatives: Python-specific (TS doesn't have this issue) +- Cancellation Handling vs Cancellation Scopes: different idioms per language +- Triggers: TS-specific pattern +- Entity Workflow Pattern: conceptual in core, implementation left to user +- Using Pydantic Models: Python-specific + +**Order alignment:** ✓ Aligned — TS# and Go# monotonically increase + +**Style alignment:** ✅ All issues fixed (Python, TypeScript, Go) +- ✅ **Queries:** TS now has "Important: must NOT modify state" note +- ✅ **Updates:** All languages now have "validators must NOT mutate state or block" note +- ✅ **Saga Pattern:** TS now has idempotency note, comments about saving compensation BEFORE activity +- ✅ **Saga Pattern:** TS now uses `log` from `@temporalio/workflow` diff --git a/.memory/alignment_checking/testing.md b/.memory/alignment_checking/testing.md new file mode 100644 index 0000000..b22a887 --- /dev/null +++ b/.memory/alignment_checking/testing.md @@ -0,0 +1,44 @@ +# testing.md + +## Section Inventory + +| Section | Core | Python | Py# | TypeScript | TS# | Go | Go# | +|---------|------|--------|-----|------------|-----|-----|-----| +| Overview | — | ✓ | 1 | ✓ | 1 | ✓ | 1 | +| Test Environment Setup | — | ✓ | 2 | ✓ | 2 | ✓ | 2 | +| Time Skipping | — | — | — | — | — | — | — | +| Activity Mocking | — | ✓ | 3 | ✓ | 3 | ✓ | 3 | +| Testing Signals and Queries | — | ✓ | 4 | ✓ | 4 | ✓ | 4 | +| Testing Failure Cases | — | ✓ | 5 | ✓ | 5 | ✓ | 5 | +| Replay Testing | — | ✓ | 6 | ✓ | 6 | ✓ | 6 | +| Activity Testing | — | ✓ | 7 | ✓ | 7 | ✓ | 7 | +| Best Practices | — | ✓ | 8 | ✓ | 8 | ✓ | 8 | + +## Style Compliance + +| Language | Status | Notes | +|----------|--------|-------| +| Python | ✓ reference | — | +| TypeScript | ✓ aligned | Added failure/activity testing | +| Go | ✓ aligned | testsuite package, testify, mock activities, TestWorkflowEnvironment | + +## Status + +**Go-specific notes:** +- Test Environment: `testsuite.WorkflowTestSuite` + `testsuite.TestWorkflowEnvironment` from `go.temporal.io/sdk/testsuite` +- Uses testify library (`suite.Suite`, `assert`, `mock`) +- Activity Mocking: `env.OnActivity(ActivityFunc, mock.Anything, ...).Return(result, nil)` — can use function replacement +- Testing Signals: `env.RegisterDelayedCallback` to send signals; `env.SignalWorkflow` +- Testing Queries: `env.QueryWorkflow("queryName")` returns `converter.EncodedValue` +- Testing Failure: `env.GetWorkflowError()` + `errors.As(err, &applicationErr)` +- Replay Testing: `worker.ReplayWorkflowHistory` with JSON history +- Activity Testing: `testsuite.TestActivityEnvironment` for isolated activity tests +- Time Skipping: built into TestWorkflowEnvironment (timers fire immediately) + +**Intentionally missing (`—`):** +- Core column: no core testing.md exists (implementation-specific) +- Time Skipping: mentioned inline (built into test environment) + +**Order alignment:** ✅ Aligned — Go sections match Python/TypeScript order + +**Style alignment:** ✅ Complete (Python, TypeScript, Go) diff --git a/.memory/alignment_checking/versioning.md b/.memory/alignment_checking/versioning.md new file mode 100644 index 0000000..ba581f7 --- /dev/null +++ b/.memory/alignment_checking/versioning.md @@ -0,0 +1,46 @@ +# versioning.md + +## Section Inventory + +| Section | Core | Core# | Python | Py# | TypeScript | TS# | Go | Go# | +|---------|------|-------|--------|-----|------------|-----|-----|-----| +| Overview | ✓ | 1 | — | — | — | — | — | — | +| Why Versioning is Needed | ✓ | 2 | — | — | — | — | — | — | +| Patching API / GetVersion API | ✓ | 3 | ✓ | 1 | ✓ | 1 | ✓ | 1 | +| Workflow Type Versioning | ✓ | 4 | ✓ | 2 | ✓ | 2 | ✓ | 2 | +| Worker Versioning | ✓ | 5 | ✓ | 3 | ✓ | 3 | ✓ | 3 | +| Choosing a Strategy | ✓ | 6 | — | — | — | — | — | — | +| Best Practices | ✓ | 7 | ✓ | 4 | ✓ | 4 | ✓ | 4 | +| Finding Workflows by Version | ✓ | 8 | — | — | — | — | — | — | +| Common Mistakes | ✓ | 9 | — | — | — | — | — | — | + +## Style Compliance + +| Language | Status | Notes | +|----------|--------|-------| +| Core | ✓ reference | Conceptual content | +| Python | ✓ aligned | Code only, refs core | +| TypeScript | ✓ aligned | Code only, refs core | +| Go | ✓ aligned | Uses `workflow.GetVersion` (not patching); code only, refs core | + +## Status + +**Go-specific notes:** +- Go uses `workflow.GetVersion(ctx, changeID, minSupported, maxSupported)` — returns a `Version` (int) +- Different from Python/TS `patched()`/`deprecatePatch()` — Go uses a version number approach +- Three-step lifecycle: add GetVersion branch -> increase minSupported -> collapse to single branch +- `workflow.DefaultVersion` constant (-1) represents pre-versioned code +- TemporalChangeVersion search attribute set automatically +- Worker Versioning works the same across all SDKs (server-side feature) +- Query filters for finding workflows by version are available + +**Intentionally missing (`—`):** +- Overview: Core-only (conceptual; languages reference core) +- Why Versioning is Needed: Core-only (conceptual; languages reference core) +- Choosing a Strategy: Core-only (conceptual; languages reference core) +- Finding Workflows by Version: Core-only section (languages cover in Query Filters subsections) +- Common Mistakes: Core-only section + +**Order alignment:** ✓ Aligned — languages focus on code: Patching/GetVersion API, Type Versioning, Worker Versioning, Best Practices + +**Style alignment:** ✅ Complete (Python, TypeScript, Go) diff --git a/.memory/correctness_checking/README.md b/.memory/correctness_checking/README.md new file mode 100644 index 0000000..98f0cac --- /dev/null +++ b/.memory/correctness_checking/README.md @@ -0,0 +1,72 @@ +# Correctness Checking + +Track verification of factual statements and code examples in reference files for the **temporal-developer** skill. + +**Skill location:** `plugins/temporal-developer/skills/temporal-developer/` +**Reference files:** `plugins/temporal-developer/skills/temporal-developer/references/` + +## File Organization + +Each file in this directory tracks correctness for a corresponding reference file. Within each file, sections are organized by language (e.g., `## TypeScript`, `## Python`). + +**Supported languages:** TypeScript, Python, Go + +**Adding a new language:** Add a new `## {Language}` section to each relevant file with a Tracking table and Detailed Notes. + +## Summary + +| File | TypeScript | Python | Go | +|------|------------|--------|-----| +| patterns.md | ✅ | partial | ✅ | +| testing.md | ✅ | partial | ✅ | +| language.md | ✅ | partial | ✅ | +| versioning.md | ✅ | partial | ✅ | +| advanced-features.md | ✅ | partial | ✅ | +| data-handling.md | ✅ | partial | ✅ | +| determinism-protection.md | ✅ | partial | ✅ | +| determinism.md | ✅ | partial | ✅ | +| error-handling.md | ✅ | partial | ✅ | +| gotchas.md | ✅ | partial | ✅ | +| observability.md | ✅ | partial | ✅ | +| ai-patterns.md | — | partial | — | +| sync-vs-async.md | — | ✅ | — | + +**Legend:** ✅ = all sections verified, partial = some sections need fixes, unchecked = not yet verified, — = N/A + +## Files + +- [patterns.md](./patterns.md) +- [testing.md](./testing.md) +- [language.md](./language.md) — top-level `{language}.md` files +- [versioning.md](./versioning.md) +- [advanced-features.md](./advanced-features.md) +- [data-handling.md](./data-handling.md) +- [determinism-protection.md](./determinism-protection.md) +- [determinism.md](./determinism.md) +- [error-handling.md](./error-handling.md) +- [gotchas.md](./gotchas.md) +- [observability.md](./observability.md) +- [ai-patterns.md](./ai-patterns.md) +- [sync-vs-async.md](./sync-vs-async.md) + +## Verification Workflow + +1. Read the section from the reference file +2. Query documentation sources: + - `mcp__context7__query-docs` with `/temporalio/sdk-typescript`, `/temporalio/sdk-python`, or `/temporalio/sdk-go` + - `mcp__temporal-docs__search_temporal_knowledge_sources` for conceptual verification +3. Compare code examples against official docs +4. Apply fixes to source file if needed +5. Update tracking table: Status, Fix Applied, Sources +6. Update Detailed Notes with verification details + +## Status Values + +- `unchecked` - Not yet verified +- `all good` - Verified correct, no changes needed +- `needs fixes` - Issues found but not yet corrected +- `FIXED` - Issues found and corrected + +## Resume Instructions + +Check Summary table for incomplete files, then find the first `unchecked` or `needs fixes` section. diff --git a/.memory/correctness_checking/advanced-features.md b/.memory/correctness_checking/advanced-features.md new file mode 100644 index 0000000..952ac22 --- /dev/null +++ b/.memory/correctness_checking/advanced-features.md @@ -0,0 +1,187 @@ +# advanced-features.md + +Correctness verification for `references/{language}/advanced-features.md`. + +## TypeScript + +**File:** `references/typescript/advanced-features.md` (relative to skill root) + +### Tracking + +| # | Section | Status | Fix Applied | Sources | +|---|---------|--------|-------------|---------| +| 1 | Schedules | FIXED | Use ScheduleOverlapPolicy.SKIP (not string literal), use intervals (recommended over cronExpressions) | context7 sdk-typescript, temporal-docs | +| 2 | Async Activity Completion | FIXED | Manually corrected to match official docs: activityInfo().taskToken, AsyncCompletionClient, CompleteAsyncError | temporal-docs | +| 3 | Worker Tuning | FIXED | Reverted to non-default values (100, 200) to demonstrate customization | context7 sdk-typescript | +| 4 | Sinks | all good | | context7 sdk-typescript | + +### Detailed Notes + +#### 1. Schedules +**Status:** FIXED + +**Fixed:** +- Use `ScheduleOverlapPolicy.SKIP` import (not string literal) to match official samples +- Use `intervals` (not `cronExpressions`) - intervals is the recommended approach for new code (cronExpressions is only for legacy migration) +- Added import for `ScheduleOverlapPolicy` from `@temporalio/client` + +--- + +#### 2. Async Activity Completion +**Status:** FIXED + +**Fixed:** Manually corrected by user to match official docs: +- `activityInfo().taskToken` (returns `Uint8Array`) +- `AsyncCompletionClient` for external completion +- `CompleteAsyncError` to signal async completion + +--- + +#### 3. Worker Tuning +**Status:** FIXED + +**Fixed:** Reverted to non-default values (100 for workflows, 200 for activities) - the point of the example is to show customization, not defaults. + +--- + +#### 4. Sinks +**Status:** all good + +**Verified:** proxySinks, Sinks imports, interface pattern, Worker sinks config, handler signature, callDuringReplay option all correct + +--- + + +## Python + +**File:** `references/python/advanced-features.md` (relative to skill root) + +### Tracking + +| # | Section | Status | Fix Applied | Sources | +|---|---------|--------|-------------|---------| +| 1 | Schedules | all good | | context7 sdk-python | +| 2 | Async Activity Completion | all good | | context7 sdk-python | +| 3 | Sandbox Customization | all good | | context7 sdk-python | +| 4 | Gevent Compatibility Warning | all good | | context7 sdk-python | +| 5 | Worker Tuning | all good | | context7 sdk-python | +| 6 | Workflow Init Decorator | needs fixes | | context7 sdk-python | +| 7 | Workflow Failure Exception Types | all good | | context7 sdk-python | + +### Detailed Notes + +#### 1. Schedules +**Status:** all good + +**Verified:** All imports, create_schedule API, ScheduleActionStartWorkflow, ScheduleSpec, handle methods all correct + +--- + +#### 2. Async Activity Completion +**Status:** all good + +**Verified:** activity.info().task_token, raise_complete_async(), get_async_activity_handle, handle methods all correct + +--- + +#### 3. Sandbox Customization +**Status:** all good + +**Verified:** Reference to determinism-protection.md path is correct + +--- + +#### 4. Gevent Compatibility Warning +**Status:** all good + +**Verified:** Gevent incompatibility claim and monkey patching explanation are accurate + +--- + +#### 5. Worker Tuning +**Status:** all good + +**Verified:** +- `ThreadPoolExecutor` import from `concurrent.futures` ✓ +- `Worker()` constructor options all correct ✓ +- `max_concurrent_workflow_tasks` option exists ✓ +- `max_concurrent_activities` option exists ✓ +- `activity_executor` option with ThreadPoolExecutor ✓ +- `graceful_shutdown_timeout` option with timedelta ✓ + +--- + +#### 6. Workflow Init Decorator +**Status:** needs fixes + +**Issues:** +- `@workflow.init` decorator and `__init__` method pattern are correct +- "Runs only on first execution, not replay" claim needs clarification +- The decorator ensures init runs before handlers/run, but the "not replay" behavior needs verification +- Purpose description is accurate + +--- + +#### 7. Workflow Failure Exception Types +**Status:** all good + +**Verified:** +- `@workflow.defn(failure_exception_types=[...])` parameter exists ✓ +- Listed exception types fail workflow instead of task ✓ +- `NondeterminismError` special case documented ✓ +- Worker-level `workflow_failure_exception_types` parameter exists ✓ +- Testing tip about `[Exception]` is valid ✓ + +--- + + +## Go + +**File:** `references/go/advanced-features.md` (relative to skill root) + +### Tracking + +| # | Section | Status | Fix Applied | Sources | +|---|---------|--------|-------------|---------| +| 1 | Schedules | all good | | temporal-docs | +| 2 | Async Activity Completion | all good | | temporal-docs | +| 3 | Worker Tuning | all good | | temporal-docs | +| 4 | Sessions | all good | | temporal-docs | + +### Detailed Notes + +#### 1. Schedules +**Status:** all good +**Verified:** +- `client.ScheduleClient().Create` API ✓ +- `client.ScheduleOptions` struct ✓ +- `client.ScheduleSpec` configuration ✓ + +--- + +#### 2. Async Activity Completion +**Status:** all good +**Verified:** +- `activity.ErrResultPending` to signal async completion ✓ +- `CompleteActivity` / `CompleteActivityByID` for external completion ✓ + +--- + +#### 3. Worker Tuning +**Status:** all good +**Verified:** +- Worker tuning options ✓ + +--- + +#### 4. Sessions +**Status:** all good +**Verified:** +- `workflow.CreateSession` API ✓ +- `workflow.CompleteSession` API ✓ +- `EnableSessionWorker` worker option ✓ +- `workflow.ErrSessionFailed` sentinel error ✓ +- `workflow.SessionOptions` struct ✓ + +--- + diff --git a/.memory/correctness_checking/ai-patterns.md b/.memory/correctness_checking/ai-patterns.md new file mode 100644 index 0000000..7a634f6 --- /dev/null +++ b/.memory/correctness_checking/ai-patterns.md @@ -0,0 +1,152 @@ +# ai-patterns.md + +Correctness verification for `references/python/ai-patterns.md` (Python only). + +## Python + +**File:** `references/python/ai-patterns.md` (relative to skill root) + +### Tracking + +| # | Section | Status | Fix Applied | Sources | +|---|---------|--------|-------------|---------| +| 1 | Overview | needs fixes | | context7 sdk-python | +| 2 | Pydantic Data Converter Setup | needs fixes | | context7 sdk-python | +| 3 | OpenAI Client Configuration | all good | | context7 openai-python, temporal-docs | +| 4 | LiteLLM Configuration | all good | | litellm docs | +| 5 | Generic LLM Activity | all good | | context7 sdk-python | +| 6 | Activity Retry Policy | all good | | context7 sdk-python | +| 7 | Tool-Calling Agent Workflow | needs fixes | | context7 sdk-python | +| 8 | Structured Outputs | needs fixes | | context7 openai-python | +| 9 | Multi-Agent Pipeline | all good | | context7 sdk-python | +| 10 | OpenAI Agents SDK Integration | needs fixes | | context7 sdk-python | +| 11 | Best Practices | all good | | context7 sdk-python | + +### Detailed Notes + +#### 1. Overview +**Status:** needs fixes + +**Issues:** +- Reference path `references/core/ai-integration.md` is INCORRECT - file does not exist +- Correct path should be `references/core/ai-patterns.md` + +--- + +#### 2. Pydantic Data Converter Setup +**Status:** needs fixes + +**Issues:** +- Import and converter name are correct (`from temporalio.contrib.pydantic import pydantic_data_converter`) +- `Client.connect()` with `data_converter` parameter placement needs verification +- Claim about "complex types like OpenAI response objects" is misleading - Pydantic converter is for Pydantic models that WRAP responses, not raw OpenAI response objects + +--- + +#### 3. OpenAI Client Configuration +**Status:** all good + +**Verified:** +- `AsyncOpenAI` import from `openai` ✓ +- `max_retries=0` recommendation is valid and explicitly recommended by Temporal docs ✓ +- `timeout` parameter accepts float value in seconds ✓ + +--- + +#### 4. LiteLLM Configuration +**Status:** all good + +**Verified:** +- `litellm.num_retries = 0` is correct module-level variable for disabling retries ✓ + +--- + +#### 5. Generic LLM Activity +**Status:** all good + +**Verified:** +- `@activity.defn` decorator ✓ +- `ApplicationError` import from `temporalio.exceptions` ✓ +- `non_retryable=True` parameter ✓ +- `next_retry_delay` parameter for rate limits ✓ +- All OpenAI exception types exist (AuthenticationError, RateLimitError, APIStatusError, APIConnectionError) ✓ +- Pydantic `BaseModel` usage ✓ + +--- + +#### 6. Activity Retry Policy +**Status:** all good + +**Verified:** +- `workflow.unsafe.imports_passed_through()` context manager ✓ +- `workflow.execute_activity()` API ✓ +- `start_to_close_timeout` parameter ✓ +- Note about automatic retry behavior is accurate ✓ + +**Note:** Unused `RetryPolicy` import is technically unnecessary but not incorrect. + +--- + +#### 7. Tool-Calling Agent Workflow +**Status:** needs fixes + +**Issues:** +- `@workflow.defn`, `@workflow.run`, `workflow.execute_activity()` patterns are all correct +- **Message accumulation pattern is problematic:** + - Code converts `messages` list to string: `current_input = f"Tool results: {messages}"` + - This loses proper message structure expected by OpenAI API + - Missing assistant's message with tool calls before tool results + - `LLMRequest` model should accept `messages` list, not just `user_input` + +**Recommended:** Either modify `LLMRequest` to accept messages list, or use `temporalio.contrib.openai_agents` integration. + +--- + +#### 8. Structured Outputs +**Status:** needs fixes + +**Issues:** +- `openai_client.beta.chat.completions.parse()` is INCORRECT +- Correct API: `openai_client.chat.completions.parse()` (no `beta` prefix) +- `response_format=AnalysisResult` (Pydantic model) is correct ✓ +- `response.choices[0].message.parsed` returns Pydantic instance is correct ✓ + +--- + +#### 9. Multi-Agent Pipeline +**Status:** all good + +**Verified:** +- `asyncio.gather(*tasks, return_exceptions=True)` pattern ✓ +- `schedule_to_close_timeout` vs `start_to_close_timeout` usage together is valid ✓ +- Parallel activity execution pattern ✓ +- Partial failure handling with `isinstance(r, Exception)` filter ✓ + +--- + +#### 10. OpenAI Agents SDK Integration +**Status:** needs fixes + +**Issues:** +- `from temporalio.contrib.openai import create_workflow_agent` is INCORRECT +- `create_workflow_agent()` function does NOT exist +- Correct module is `temporalio.contrib.openai_agents` +- Correct API uses `OpenAIAgentsPlugin` as a client plugin: + ```python + from temporalio.contrib.openai_agents import OpenAIAgentsPlugin, ModelActivityParameters + client = await Client.connect(..., plugins=[OpenAIAgentsPlugin(...)]) + ``` +- `Agent`, `Runner` imports from `agents` are correct ✓ +- "Automatically dispatches to activities for LLM calls" claim is accurate ✓ + +--- + +#### 11. Best Practices +**Status:** all good + +**Verified:** +- All 8 best practices are valid ✓ +- "Disable retries in LLM clients" recommendation is correct - prevents double-retry with Temporal ✓ + +--- + diff --git a/.memory/correctness_checking/data-handling.md b/.memory/correctness_checking/data-handling.md new file mode 100644 index 0000000..5b5b5ac --- /dev/null +++ b/.memory/correctness_checking/data-handling.md @@ -0,0 +1,332 @@ +# data-handling.md + +Correctness verification for `references/{language}/data-handling.md`. + +## TypeScript + +**File:** `references/typescript/data-handling.md` (relative to skill root) + +### Tracking + +| # | Section | Status | Fix Applied | Sources | +|---|---------|--------|-------------|---------| +| 1 | Overview | all good | | context7 sdk-typescript | +| 2 | Default Data Converter | FIXED | Clarified Protobuf requires custom converter | context7 sdk-typescript | +| 3 | Custom Data Converter | FIXED | Uses payloadConverterPath pattern | context7 sdk-typescript | +| 4 | Payload Codec (Encryption) | FIXED | Changed to payloadCodecs (plural, array) | context7 sdk-typescript | +| 5 | Search Attributes | all good | | context7 sdk-typescript | +| 6 | Workflow Memo | all good | | context7 sdk-typescript | +| 7 | Protobuf Support | all good | | context7 sdk-typescript | +| 8 | Large Payloads | FIXED | Import already present | context7 sdk-typescript | +| 9 | Best Practices | all good | | context7 sdk-typescript | + +### Detailed Notes + +#### 1. Overview +**Status:** all good + +**Verified:** Data converter role description is accurate + +--- + +#### 2. Default Data Converter +**Status:** FIXED + +**Fixed:** Removed misleading Protobuf claim, added note that Protobuf requires `DefaultPayloadConverterWithProtobufs`. + +--- + +#### 3. Custom Data Converter +**Status:** FIXED + +**Fixed:** Uses `payloadConverterPath: require.resolve()` pattern, added Payload import, uses generic ``. + +--- + +#### 4. Payload Codec (Encryption) +**Status:** FIXED + +**Fixed:** Changed `payloadCodec` to `payloadCodecs` (plural, as array). + +--- + +#### 5. Search Attributes +**Status:** all good + +**Verified:** searchAttributes option, array format, upsertSearchAttributes, workflowInfo().searchAttributes, client.workflow.list, query syntax all correct + +--- + +#### 6. Workflow Memo +**Status:** all good + +**Verified:** memo option, workflowInfo().memo, distinction from search attributes all correct + +--- + +#### 7. Protobuf Support +**Status:** all good + +**Verified:** Import path `@temporalio/common/lib/protobufs` and `protobufRoot` option are correct + +--- + +#### 8. Large Payloads +**Status:** FIXED + +**Fixed:** Import already present in current file (verified correct). + +--- + +#### 9. Best Practices +**Status:** all good + +**Verified:** All 6 best practices are valid and aligned with SDK documentation + +--- + + +## Python + +**File:** `references/python/data-handling.md` (relative to skill root) + +### Tracking + +| # | Section | Status | Fix Applied | Sources | +|---|---------|--------|-------------|---------| +| 1 | Overview | all good | | context7 sdk-python | +| 2 | Default Data Converter | all good | | context7 sdk-python | +| 3 | Pydantic Integration | all good | | context7 sdk-python | +| 4 | Custom Data Conversion | all good | | context7 sdk-python, samples-python | +| 5 | Payload Encryption | needs fixes | | context7 sdk-python | +| 6 | Search Attributes | needs fixes | | context7 sdk-python, sdk source | +| 7 | Querying Workflows by Search Attributes | all good | | context7 sdk-python, temporal-docs | +| 8 | Workflow Memo | needs fixes | | context7 sdk-python, sdk source | +| 9 | Large Payloads | all good | | temporal-docs | +| 10 | Deterministic APIs for Values | all good | | context7 sdk-python, sdk source | +| 11 | Best Practices | all good | | context7 sdk-python, temporal-docs | + +### Detailed Notes + +#### 1. Overview +**Status:** all good + +**Verified:** +- Data converter role description is accurate ✓ + +--- + +#### 2. Default Data Converter +**Status:** all good + +**Verified:** +- Supported types list is accurate (intentionally simplified) ✓ +- `None`, `bytes`, Protobuf messages, JSON-serializable types all correct ✓ +- SDK actually supports additional types (dataclasses, UUID, datetime) but examples listed are correct ✓ + +--- + +#### 3. Pydantic Integration +**Status:** all good + +**Verified:** +- `pydantic.BaseModel` subclass as workflow input/output type ✓ +- `pydantic_data_converter` import from `temporalio.contrib.pydantic` ✓ +- Client configuration with `data_converter=pydantic_data_converter` ✓ +- Automatic validation claim is accurate ✓ + +--- + +#### 4. Custom Data Conversion +**Status:** all good + +**Verified:** +- `EncodingPayloadConverter` and `CompositePayloadConverter` approach is correct ✓ +- Both sample URLs are valid and accessible ✓ + +--- + +#### 5. Payload Encryption +**Status:** needs fixes + +**Issues:** +- `PayloadCodec` import from `temporalio.converter` is correct ✓ +- `Payload` import from `temporalio.api.common.v1` is correct ✓ +- `encode()` and `decode()` methods are correct ✓ +- `Sequence[Payload]` parameter and `list[Payload]` return type are correct ✓ +- `DataConverter(payload_codec=...)` configuration is correct ✓ +- **`asyncio.to_thread()` usage is NOT in official samples** - official encryption sample calls crypto synchronously +- Missing `import asyncio` if keeping `asyncio.to_thread()` pattern +- The pattern is a valid optimization but not official - should add note or align with official samples + +--- + +#### 6. Search Attributes +**Status:** needs fixes + +**Issues:** +- Imports from `temporalio.common` are correct ✓ +- `SearchAttributeKey.for_keyword()`, `.for_float()`, `.for_datetime()` factory methods are correct ✓ +- `client.start_workflow()` with `search_attributes=TypedSearchAttributes([...])` is correct ✓ +- **`workflow.upsert_search_attributes()` API is INCORRECT:** + - Document shows: `workflow.upsert_search_attributes(TypedSearchAttributes([SearchAttributePair(...)]))` + - Correct API: `workflow.upsert_search_attributes([KEY.value_set(value)])` + - Function takes `Sequence[SearchAttributeUpdate]`, not `TypedSearchAttributes` + - Use `.value_set()` or `.value_unset()` on `SearchAttributeKey` + +--- + +#### 7. Querying Workflows by Search Attributes +**Status:** all good + +**Verified:** +- `client.list_workflows(query)` API ✓ +- Query string syntax with `=`, `OR` operators ✓ +- Async iteration over results ✓ + +--- + +#### 8. Workflow Memo +**Status:** needs fixes + +**Issues:** +- `memo` parameter type is correct (dict works as Mapping) ✓ +- "Not searchable" distinction is correctly stated ✓ +- **`workflow.memo_value()` signature is incomplete:** + - Document shows: `workflow.memo_value("key", type_hint=Type)` + - Missing `default` parameter: `workflow.memo_value(key, default=..., type_hint=...)` + - Without default, `KeyError` is raised if key missing + - Should document: `workflow.memo_value("key", default="", type_hint=str)` + +--- + +#### 9. Large Payloads +**Status:** all good + +**Verified:** +- External storage pattern (S3/GCS) ✓ +- Payload Codec compression suggestion ✓ +- Chunking suggestion ✓ +- Reference pattern code example is correct ✓ + +--- + +#### 10. Deterministic APIs for Values +**Status:** all good + +**Verified:** +- `workflow.uuid4()` returns deterministic UUID based on `random()` ✓ +- `workflow.random()` returns deterministically-seeded pseudo-RNG ✓ +- `rng.randint(a, b)` API works (returns Python's `random.Random` class) ✓ +- "Same on replay" claim is accurate - both are deterministically-seeded ✓ + +--- + +#### 11. Best Practices +**Status:** all good + +**Verified:** +- All 6 best practices are valid ✓ +- 2MB payload recommendation matches Temporal Cloud limits ✓ +- `workflow.uuid4()` and `workflow.random()` recommendation is correct ✓ + +--- + + +## Go + +**File:** `references/go/data-handling.md` (relative to skill root) + +### Tracking + +| # | Section | Status | Fix Applied | Sources | +|---|---------|--------|-------------|---------| +| 1 | Overview | all good | | temporal-docs | +| 2 | Default Data Converter | all good | | temporal-docs | +| 3 | Custom Data Converter | FIXED | Added full PayloadConverter example (msgpack), CompositeDataConverter usage, per-call override, deadlock detection note | temporal-docs | +| 4 | Composition of Payload Converters | all good | | temporal-docs | +| 5 | Protobuf Support | all good | | temporal-docs | +| 6 | Payload Encryption | all good | | temporal-docs | +| 7 | Search Attributes | all good | | temporal-docs | +| 8 | Workflow Memo | all good | | temporal-docs | +| 9 | Best Practices | all good | | temporal-docs | + +### Detailed Notes + +#### 1. Overview +**Status:** all good +**Verified:** +- `converter.DataConverter` interface for serialization ✓ +- Default JSON conversion ✓ + +--- + +#### 2. Default Data Converter +**Status:** all good +**Verified:** +- `CompositeDataConverter` applies converters in order ✓ + +--- + +#### 3. Custom Data Converter +**Status:** FIXED + +**Issue 1:** Listed 5 interface methods but actual `converter.DataConverter` has 6 -- was missing `ToStrings`. Fixed. + +**Issue 2 (PR #38 feedback):** Section had no substantive content — no example of how to actually implement a custom converter. Rewrote with full working example. + +**Fix Applied:** +- Shows `PayloadConverter` interface (the right abstraction for most users, not the full `DataConverter`) +- Full msgpack `PayloadConverter` implementation showing all 4 methods (`ToPayload` returning nil for unhandled types, `FromPayload` checking encoding, `ToString` for UI, `Encoding`) +- `converter.MetadataEncoding` metadata key usage +- `converter.NewCompositeDataConverter` composition pattern +- Per-activity override via `workflow.WithDataConverter` +- `workflow.DataConverterWithoutDeadlockDetection` note for remote-call converters (e.g. KMS) + +**Sources:** temporal-docs (pkg.go.dev/go.temporal.io/sdk/converter, docs.temporal.io/develop/go/converters-and-encryption) + +--- + +#### 4. Composition of Payload Converters +**Status:** all good +**Verified:** +- Payload converter composition pattern ✓ + +--- + +#### 5. Protobuf Support +**Status:** all good +**Verified:** +- Protobuf as first-class supported format ✓ + +--- + +#### 6. Payload Encryption +**Status:** all good +**Verified:** +- `converter.PayloadCodec` interface ✓ +- `Encode`/`Decode` methods ✓ + +--- + +#### 7. Search Attributes +**Status:** all good +**Verified:** +- Search attribute APIs ✓ + +--- + +#### 8. Workflow Memo +**Status:** all good +**Verified:** +- Memo APIs ✓ + +--- + +#### 9. Best Practices +**Status:** all good +**Verified:** +- All best practices valid ✓ + +--- + diff --git a/.memory/correctness_checking/determinism-protection.md b/.memory/correctness_checking/determinism-protection.md new file mode 100644 index 0000000..a16068b --- /dev/null +++ b/.memory/correctness_checking/determinism-protection.md @@ -0,0 +1,234 @@ +# determinism-protection.md + +Correctness verification for `references/{language}/determinism-protection.md`. + +## TypeScript + +**File:** `references/typescript/determinism-protection.md` (relative to skill root) + +### Tracking + +| # | Section | Status | Fix Applied | Sources | +|---|---------|--------|-------------|---------| +| 1 | Overview | FIXED | Removed "unique to TS" claim | context7 sdk-typescript | +| 2 | Import Blocking | FIXED | Clarified ignoreModules excludes | context7 sdk-typescript | +| 3 | Function Replacement | FIXED | Removed bad activity advice | SDK team feedback | + +### Detailed Notes + +#### 1. Overview +**Status:** FIXED + +**Fixed:** Removed "unique to TypeScript SDK" claim (Python also has sandbox). + +--- + +#### 2. Import Blocking +**Status:** FIXED + +**Fixed:** Clarified that ignoreModules EXCLUDES modules, added note that excluded modules are unavailable at runtime and node: prefix note. + +--- + +#### 3. Function Replacement +**Status:** FIXED + +**SDK team feedback:** Removed misleading advice about retrieving time in an activity. Getting time via activity doesn't provide better real-world time estimate than Date.now(). + +**Verified:** Math.random(), Date, setTimeout() replacements all correct. Date behavior, code example, FinalizationRegistry/WeakRef removal, GC explanation all accurate. + +--- + + +## Python + +**File:** `references/python/determinism-protection.md` (relative to skill root) + +### Tracking + +| # | Section | Status | Fix Applied | Sources | +|---|---------|--------|-------------|---------| +| 1 | Overview | needs fixes | | context7 sdk-python, temporal-docs | +| 2 | How the Sandbox Works | all good | | context7 sdk-python | +| 3 | Forbidden Operations | all good | | context7 sdk-python, sdk source | +| 4 | Pass-Through Pattern | all good | | context7 sdk-python | +| 5 | Importing Activities | all good | | context7 sdk-python | +| 6 | Disabling the Sandbox | all good | | context7 sdk-python | +| 7 | Customizing Invalid Module Members | needs fixes | | context7 sdk-python | +| 8 | Import Notification Policy | all good | | sdk source (v1.21.1) | +| 9 | Disable Lazy sys.modules Passthrough | all good | | sdk source | +| 10 | File Organization | needs fixes | | context7 sdk-python | +| 11 | Common Issues | needs fixes | | context7 sdk-python, sdk source | +| 12 | Best Practices | all good | | context7 sdk-python | + +### Detailed Notes + +#### 1. Overview +**Status:** needs fixes + +**Issues:** +- "Unique to the Python SDK" claim is INCORRECT +- TypeScript SDK also has sandbox protection (V8 isolates + Webpack bundling) +- Should remove uniqueness claim or clarify that Python's approach (exec + proxy objects) is distinct + +--- + +#### 2. How the Sandbox Works +**Status:** all good + +**Verified:** +- "Isolates global state via `exec` compilation" ✓ +- "Restricts non-deterministic library calls via proxy objects" ✓ +- "Passes through standard library with restrictions" ✓ +- "Reloads workflow files on each execution" ✓ + +--- + +#### 3. Forbidden Operations +**Status:** all good + +**Verified:** +- Direct I/O forbidden (socket, http.client, open, pathlib.Path) ✓ +- `threading` module blocked ✓ +- `subprocess` blocked ✓ +- Global state modification blocked ✓ +- `time.sleep()` blocked ✓ + +--- + +#### 4. Pass-Through Pattern +**Status:** all good + +**Verified:** +- `workflow.unsafe.imports_passed_through()` context manager ✓ +- Use cases listed are accurate ✓ +- Note about top-of-file imports is correct ✓ + +--- + +#### 5. Importing Activities +**Status:** all good + +**Verified:** +- Pass-through required for activity imports ✓ +- `workflow.execute_activity()` API with activity function reference ✓ +- `start_to_close_timeout` parameter ✓ + +--- + +#### 6. Disabling the Sandbox +**Status:** all good + +**Verified:** +- `workflow.unsafe.sandbox_unrestricted()` context manager exists ✓ +- "Per-block escape hatch" description is accurate ✓ +- Warning about losing determinism checks is present ✓ + +--- + +#### 7. Customizing Invalid Module Members +**Status:** needs fixes + +**Issues:** +- Import path is INCORRECT: `temporalio.worker.workflow_sandbox` should be `temporalio.worker_sandbox` +- All other APIs (`SandboxRestrictions.default`, `dataclasses.replace()`, `with_child_unrestricted()`, etc.) are correct +- Affects multiple code blocks in the section (lines 101-105, 134-136, 167) + +--- + +#### 8. Import Notification Policy +**Status:** all good + +**Verified:** +- `SandboxRestrictions.default.with_import_notification_policy()` API ✓ +- `workflow.SandboxImportNotificationPolicy` enum exists as `enum.Flag` ✓ +- All enum values correct: WARN_ON_DYNAMIC_IMPORT (2), WARN_ON_UNINTENTIONAL_PASSTHROUGH (4), RAISE_ON_UNINTENTIONAL_PASSTHROUGH (8), SILENT (1) ✓ +- `workflow.unsafe.sandbox_import_notification_policy()` context manager exists ✓ + +--- + +#### 9. Disable Lazy sys.modules Passthrough +**Status:** all good + +**Verified:** +- `disable_lazy_sys_module_passthrough` option exists on `SandboxRestrictions` ✓ +- Behavior description is accurate ✓ + +--- + +#### 10. File Organization +**Status:** needs fixes + +**Issues:** +- "Reloads workflow definition files on every execution" is slightly imprecise +- It's specifically NON-STANDARD library imports that cause overhead, not all file contents +- Standard library and Temporal SDK modules are passed through (not re-imported) +- Should clarify that performance is tied to import overhead, not general file size + +--- + +#### 11. Common Issues +**Status:** needs fixes + +**Issues:** +- Import error message is FABRICATED - actual error is `RestrictedWorkflowAccessError: Cannot access X from inside a workflow...` +- Pass-through fix pattern is correct ✓ +- Library caching explanation needs clarification - issue occurs specifically with pass-through modules that maintain mutable internal state + +--- + +#### 12. Best Practices +**Status:** all good + +**Verified:** +- All 5 best practices are valid ✓ + +--- + + +## Go + +**File:** `references/go/determinism-protection.md` (relative to skill root) + +### Tracking + +| # | Section | Status | Fix Applied | Sources | +|---|---------|--------|-------------|---------| +| 1 | Overview | all good | | temporal-docs | +| 2 | workflowcheck Static Analysis | all good | | temporal-docs | +| 3 | Determinism Rules | all good | | temporal-docs | +| 4 | Best Practices | all good | | temporal-docs | + +### Detailed Notes + +#### 1. Overview +**Status:** all good +**Verified:** +- No runtime sandbox, developer convention + optional static analysis ✓ +- Limited runtime command-ordering check mentioned ✓ + +--- + +#### 2. workflowcheck Static Analysis +**Status:** all good +**Verified:** +- Tool path `go.temporal.io/sdk/contrib/tools/workflowcheck` ✓ +- Flagged operations list (I/O, goroutines, time, rand, etc.) ✓ +- `//workflowcheck:ignore` annotation syntax ✓ + +--- + +#### 3. Determinism Rules +**Status:** all good +**Verified:** +- Rules for workflow code correctness ✓ + +--- + +#### 4. Best Practices +**Status:** all good +**Verified:** +- All best practices valid ✓ + +--- + diff --git a/.memory/correctness_checking/determinism.md b/.memory/correctness_checking/determinism.md new file mode 100644 index 0000000..4d948d3 --- /dev/null +++ b/.memory/correctness_checking/determinism.md @@ -0,0 +1,234 @@ +# determinism.md + +Correctness verification for `references/{language}/determinism.md`. + +## TypeScript + +**File:** `references/typescript/determinism.md` (relative to skill root) + +### Tracking + +| # | Section | Status | Fix Applied | Sources | +|---|---------|--------|-------------|---------| +| 1 | Overview | all good | | context7 sdk-typescript | +| 2 | Why Determinism Matters | all good | | context7 sdk-typescript | +| 3 | Temporal's V8 Sandbox | all good | | context7 sdk-typescript | +| 4 | Deterministic UUID Generation | all good | | context7 sdk-typescript | +| 5 | Forbidden Operations | FIXED | Removed console.log from forbidden list | SDK team feedback | +| 6 | Testing Replay Compatibility | FIXED | Changed Replayer to Worker.runReplayHistory() | context7 sdk-typescript | +| 7 | Best Practices | all good | | context7 sdk-typescript | + +### Detailed Notes + +#### 1. Overview +**Status:** all good + +**Verified:** V8 sandbox automatic determinism claim is accurate + +--- + +#### 2. Why Determinism Matters +**Status:** all good + +**Verified:** History Replay explanation, scenarios (crash, cache eviction, long timer), determinism requirement all correct + +--- + +#### 3. Temporal's V8 Sandbox +**Status:** all good + +**Verified:** Sandbox replacements, Math.random() with same seed, reference to determinism-protection.md all correct + +--- + +#### 4. Deterministic UUID Generation +**Status:** all good + +**Verified:** uuid4 import, workflow seeded PRNG, same UUID during replay, use cases all correct + +--- + +#### 5. Forbidden Operations +**Status:** FIXED + +**SDK team feedback:** `console.log` is NOT forbidden - the SDK patches console.log/warn/error to include workflow ID. Removed from forbidden operations list. + +**Verified:** fs forbidden, fetch() forbidden, activities recommendation all correct + +--- + +#### 6. Testing Replay Compatibility +**Status:** FIXED + +**Issues:** +- "Replayer" class reference should be `Worker.runReplayHistory()` - no Replayer class in TS SDK +- Reference to testing.md path is correct + +--- + +#### 7. Best Practices +**Status:** all good + +**Verified:** All 5 best practices are valid + +--- + + +## Python + +**File:** `references/python/determinism.md` (relative to skill root) + +### Tracking + +| # | Section | Status | Fix Applied | Sources | +|---|---------|--------|-------------|---------| +| 1 | Overview | all good | | context7 sdk-python | +| 2 | Why Determinism Matters | all good | | context7 sdk-python | +| 3 | Forbidden Operations | needs fixes | | context7 sdk-python | +| 4 | Safe Builtin Alternatives | needs fixes | | context7 sdk-python, sdk source | +| 5 | Testing Replay Compatibility | all good | | context7 sdk-python | +| 6 | Sandbox Behavior | all good | | context7 sdk-python | +| 7 | Best Practices | needs fixes | | context7 sdk-python | + +### Detailed Notes + +#### 1. Overview +**Status:** all good + +**Verified:** +- Sandbox automatic protection claim is accurate ✓ + +--- + +#### 2. Why Determinism Matters +**Status:** all good + +**Verified:** +- History Replay explanation is accurate ✓ +- Scenarios: crash, cache eviction, long timer are all correct ✓ + +--- + +#### 3. Forbidden Operations +**Status:** needs fixes + +**Issues:** +- List is correct but INCOMPLETE +- Missing: `set` iteration (non-deterministic ordering) +- Missing: Raw randomness (`random` module) +- "and so on" is vague - consider being more specific + +--- + +#### 4. Safe Builtin Alternatives +**Status:** needs fixes + +**Issues:** +- All replacements are technically correct +- **Inconsistency:** Table uses `workflow.new_random()` but Best Practices section says `workflow.random()` +- Both exist and are valid, but should be consistent +- Recommend using `workflow.random()` throughout (simpler approach) + +--- + +#### 5. Testing Replay Compatibility +**Status:** all good + +**Verified:** +- `Replayer` class mention is correct ✓ +- Reference to `references/python/testing.md` path follows consistent pattern ✓ + +--- + +#### 6. Sandbox Behavior +**Status:** all good + +**Verified:** +- Sandbox behavior bullets match determinism-protection.md ✓ +- Reference to `references/python/determinism-protection.md` path is correct ✓ + +--- + +#### 7. Best Practices +**Status:** needs fixes + +**Issues:** +- Best Practices list itself is accurate ✓ +- **Internal inconsistency:** Table in §4 (Safe Builtin Alternatives) uses `workflow.new_random()` but Best Practices #2 says `workflow.random()` +- Both APIs exist but should be consistent - recommend `workflow.random()` throughout + +--- + + +## Go + +**File:** `references/go/determinism.md` (relative to skill root) + +### Tracking + +| # | Section | Status | Fix Applied | Sources | +|---|---------|--------|-------------|---------| +| 1 | Overview | all good | | temporal-docs | +| 2 | Why Determinism Matters: History Replay | all good | | temporal-docs | +| 3 | SDK Protection | all good | | temporal-docs | +| 4 | Forbidden Operations | all good | | temporal-docs | +| 5 | Safe Builtin Alternatives | all good | | temporal-docs | +| 6 | Testing Replay Compatibility | all good | | temporal-docs | +| 7 | Best Practices | all good | | temporal-docs | + +### Detailed Notes + +#### 1. Overview +**Status:** all good +**Verified:** +- No runtime sandbox, developer convention-based determinism ✓ +- `workflowcheck` static analysis tool reference ✓ + +--- + +#### 2. Why Determinism Matters: History Replay +**Status:** all good +**Verified:** +- History Replay explanation ✓ +- Reference to `references/core/determinism.md` ✓ + +--- + +#### 3. SDK Protection +**Status:** all good +**Verified:** +- No automatic sandbox, limited runtime command-ordering check ✓ + +--- + +#### 4. Forbidden Operations +**Status:** all good +**Verified:** +- Native goroutines, channels, time, rand, I/O all listed as forbidden ✓ + +--- + +#### 5. Safe Builtin Alternatives +**Status:** all good +**Verified:** +- `workflow.Now`, `workflow.Sleep`, `workflow.SideEffect`, `workflow.Go`, `workflow.NewChannel` ✓ + +--- + +#### 6. Testing Replay Compatibility +**Status:** all good +**Verified:** +- `worker.NewWorkflowReplayer` API ✓ +- `ReplayWorkflowHistoryFromJSONFile` API ✓ + +**Style nit:** Replay testing passes `nil` for logger param (functional but could show logger usage). Not a correctness issue. + +--- + +#### 7. Best Practices +**Status:** all good +**Verified:** +- All best practices valid ✓ + +--- + diff --git a/.memory/correctness_checking/error-handling.md b/.memory/correctness_checking/error-handling.md new file mode 100644 index 0000000..121330d --- /dev/null +++ b/.memory/correctness_checking/error-handling.md @@ -0,0 +1,271 @@ +# error-handling.md + +Correctness verification for `references/{language}/error-handling.md`. + +## TypeScript + +**File:** `references/typescript/error-handling.md` (relative to skill root) + +### Tracking + +| # | Section | Status | Fix Applied | Sources | +|---|---------|--------|-------------|---------| +| 1 | Overview | all good | | context7 sdk-typescript | +| 2 | Application Failures | FIXED | Verified ApplicationFailure.create() is correct | context7 sdk-typescript | +| 3 | Activity Errors | FIXED | Import from @temporalio/activity | context7 sdk-typescript | +| 4 | Handling Errors in Workflows | all good | | context7 sdk-typescript | +| 5 | Retry Configuration | all good | | context7 sdk-typescript | +| 6 | Timeout Configuration | all good | | context7 sdk-typescript | +| 7 | Workflow Failure | all good | | context7 sdk-typescript | +| 8 | Idempotency | all good | | context7 sdk-typescript | +| 9 | Best Practices | FIXED | Clarified log import for workflows vs activities | context7 sdk-typescript | + +### Detailed Notes + +#### 1. Overview +**Status:** all good + +**Verified:** ApplicationFailure description and non-retryable support claim are accurate + +--- + +#### 2. Application Failures +**Status:** FIXED + +**Fixed:** Verified ApplicationFailure.create() API is correct (both .create() and .nonRetryable() are valid). + +--- + +#### 3. Activity Errors +**Status:** FIXED + +**Fixed:** Import from `@temporalio/activity` for activities (re-exports from @temporalio/common). + +--- + +#### 4. Handling Errors in Workflows +**Status:** all good + +**Verified:** imports, instanceof check, err.type/message properties, re-throw pattern all correct + +--- + +#### 5. Retry Configuration +**Status:** all good + +**Verified:** retry option, all interval/attempts options, nonRetryableErrorTypes, defaults note all correct + +--- + +#### 6. Timeout Configuration +**Status:** all good + +**Verified:** startToCloseTimeout, scheduleToCloseTimeout, heartbeatTimeout descriptions all accurate + +--- + +#### 7. Workflow Failure +**Status:** all good + +**Verified:** ApplicationFailure pattern, nonRetryable warning, caller-controlled retries explanation all correct + +--- + +#### 8. Idempotency +**Status:** all good + +**Verified:** Reference to core/patterns.md path is correct + +--- + +#### 9. Best Practices +**Status:** FIXED + +**Fixed:** Clarified log import: @temporalio/workflow for workflows, @temporalio/activity for activities. + +--- + + +## Python + +**File:** `references/python/error-handling.md` (relative to skill root) + +### Tracking + +| # | Section | Status | Fix Applied | Sources | +|---|---------|--------|-------------|---------| +| 1 | Overview | all good | | context7 sdk-python | +| 2 | Application Errors | all good | | context7 sdk-python | +| 3 | Non-Retryable Errors | all good | | context7 sdk-python | +| 4 | Handling Activity Errors | all good | | context7 sdk-python | +| 5 | Retry Policy Configuration | all good | | context7 sdk-python | +| 6 | Timeout Configuration | all good | | context7 sdk-python | +| 7 | Workflow Failure | needs fixes | | context7 sdk-python | +| 8 | Best Practices | all good | | context7 sdk-python | + +### Detailed Notes + +#### 1. Overview +**Status:** all good + +**Verified:** +- `ApplicationError` for application-specific errors ✓ +- Comprehensive retry policy configuration ✓ +- Applies to activities, child workflows, Nexus operations ✓ + +--- + +#### 2. Application Errors +**Status:** all good + +**Verified:** +- `from temporalio.exceptions import ApplicationError` ✓ +- `ApplicationError(message, type=...)` constructor signature ✓ +- `@activity.defn` decorator context ✓ + +--- + +#### 3. Non-Retryable Errors +**Status:** all good + +**Verified:** +- `non_retryable=True` parameter ✓ +- Behavior: prevents activity retries ✓ +- Example use case (invalid credit card) matches official docs ✓ + +--- + +#### 4. Handling Activity Errors +**Status:** all good + +**Verified:** +- `from temporalio.exceptions import ActivityError, ApplicationError` ✓ +- `ActivityError` is subclass of `FailureError` ✓ +- `workflow.logger.error()` API ✓ +- Try/except/raise pattern ✓ + +--- + +#### 5. Retry Policy Configuration +**Status:** all good + +**Verified:** +- `RetryPolicy` import from `temporalio.common` ✓ +- All RetryPolicy parameters (`maximum_interval`, `maximum_attempts`, `non_retryable_error_types`) ✓ +- Note about preferring defaults is valid guidance ✓ + +--- + +#### 6. Timeout Configuration +**Status:** all good + +**Verified:** +- `start_to_close_timeout` - "Single attempt" ✓ +- `schedule_to_close_timeout` - "Including retries" ✓ +- `heartbeat_timeout` - "Between heartbeats" ✓ + +--- + +#### 7. Workflow Failure +**Status:** needs fixes + +**Issues:** +- Code example for raising `ApplicationError` in workflow is correct ✓ +- **Note is misleading:** "Do not use `non_retryable=` with `ApplicationError` inside a workflow" +- `non_retryable` parameter IS valid for `ApplicationError` in workflows per SDK docs +- The SDK says: "ApplicationError should be used; this allows for marking the error as non-retryable" +- The difference is that workflow retry behavior is controlled by the caller's retry policy, not the exception's `non_retryable` flag +- **Recommendation:** Clarify the note to explain the behavioral difference rather than saying "do not use" + +--- + +#### 8. Best Practices +**Status:** all good + +**Verified:** +- All 6 best practices are valid ✓ +- Reference to `references/core/patterns.md` path is correct ✓ +- "Mark permanent failures as non-retryable" guidance ✓ +- "Design code to be idempotent" guidance ✓ + +--- + + +## Go + +**File:** `references/go/error-handling.md` (relative to skill root) + +### Tracking + +| # | Section | Status | Fix Applied | Sources | +|---|---------|--------|-------------|---------| +| 1 | Overview | all good | | temporal-docs | +| 2 | Application Errors | all good | | temporal-docs | +| 3 | Non-Retryable Errors | all good | | temporal-docs | +| 4 | Handling Activity Errors in Workflows | all good | | temporal-docs | +| 5 | Retry Configuration | all good | | temporal-docs | +| 6 | Timeout Configuration | all good | | temporal-docs | +| 7 | Workflow Failure | all good | | temporal-docs | +| 8 | Best Practices | all good | | temporal-docs | + +### Detailed Notes + +#### 1. Overview +**Status:** all good +**Verified:** +- Error return values (not exceptions) pattern ✓ +- `*temporal.ActivityError` wrapping, `errors.As` unwrapping ✓ + +--- + +#### 2. Application Errors +**Status:** all good +**Verified:** +- `temporal.NewApplicationError(message, errType, cause, details...)` ✓ + +--- + +#### 3. Non-Retryable Errors +**Status:** all good +**Verified:** +- `temporal.NewNonRetryableApplicationError` API ✓ + +--- + +#### 4. Handling Activity Errors in Workflows +**Status:** all good +**Verified:** +- `errors.As(err, &appErr)` pattern for unwrapping ✓ +- `appErr.Type()` for error type checking ✓ + +--- + +#### 5. Retry Configuration +**Status:** all good +**Verified:** +- `temporal.RetryPolicy` struct fields (`InitialInterval`, `BackoffCoefficient`, `MaximumInterval`, `MaximumAttempts`, `NonRetryableErrorTypes`) ✓ + +--- + +#### 6. Timeout Configuration +**Status:** all good +**Verified:** +- `ActivityOptions` timeout fields (`StartToCloseTimeout`, `ScheduleToCloseTimeout`, `HeartbeatTimeout`) ✓ + +--- + +#### 7. Workflow Failure +**Status:** all good +**Verified:** +- Returning error from workflow function ✓ +- `temporal.NewApplicationError` usage in workflows ✓ + +--- + +#### 8. Best Practices +**Status:** all good +**Verified:** +- All best practices valid ✓ + +--- + diff --git a/.memory/correctness_checking/gotchas.md b/.memory/correctness_checking/gotchas.md new file mode 100644 index 0000000..548c3e6 --- /dev/null +++ b/.memory/correctness_checking/gotchas.md @@ -0,0 +1,373 @@ +# gotchas.md + +Correctness verification for `references/{language}/gotchas.md`. + +## TypeScript + +**File:** `references/typescript/gotchas.md` (relative to skill root) + +### Tracking + +| # | Section | Status | Fix Applied | Sources | +|---|---------|--------|-------------|---------| +| 1 | Activity Imports - Type vs Implementation | all good | | context7 sdk-typescript | +| 2 | Activity Imports - Node.js Modules | all good | | context7 sdk-typescript | +| 3 | Bundling Issues - workflowsPath in Production | FIXED | Added new gotcha section | SDK team feedback | +| 4 | Bundling Issues - Missing Dependencies | FIXED | Clarified ignoreModules excludes modules | context7 sdk-typescript | +| 5 | Bundling Issues - Version Mismatches | all good | | context7 sdk-typescript | +| 6 | Wrong Retry Classification | all good | | context7 sdk-typescript | +| 7 | Cancellation - Not Handling Workflow | all good | | context7 sdk-typescript | +| 7b | Cancellation - Not Handling Activity | FIXED | Added activity cancellation section | SDK team feedback | +| 8 | Heartbeating - Forgetting to Heartbeat | all good | | context7 sdk-typescript | +| 9 | Heartbeating - Timeout Too Short | all good | | context7 sdk-typescript | +| 10 | Testing - Not Testing Failures | all good | | context7 sdk-typescript | +| 11 | Testing - Not Testing Replay | FIXED | Fixed fs.promises.readFile pattern | context7 sdk-typescript | +| 12 | Timers and Sleep | all good | | context7 sdk-typescript | + +### Detailed Notes + +#### 1. Activity Imports - Type vs Implementation +**Status:** all good + +**Verified:** +- BAD pattern: `import * as activities from './activities'` ✓ +- GOOD pattern: `import type * as activities from './activities'` ✓ +- V8 sandbox bundling explanation is accurate ✓ + +--- + +#### 2. Activity Imports - Node.js Modules +**Status:** all good + +**Verified:** +- `fs` import example as BAD ✓ +- Activity delegation as GOOD pattern ✓ +- Sandbox restriction explanation is accurate ✓ + +--- + +#### 3. Bundling Issues - workflowsPath in Production +**Status:** FIXED + +**SDK team feedback:** `workflowsPath` runs bundler at Worker startup (slow). Should use `workflowBundle` with pre-bundled code for production. Added new gotcha section with example showing build-time bundling with `bundleWorkflowCode()`. Also updated examples in typescript.md, advanced-features.md, versioning.md, determinism-protection.md to caveat `workflowsPath` usage. + +--- + +#### 4. Bundling Issues - Missing Dependencies +**Status:** FIXED + +**Fixed:** Clarified that ignoreModules EXCLUDES modules and they are completely unavailable at workflow runtime. + +--- + +#### 5. Bundling Issues - Version Mismatches +**Status:** all good + +**Verified:** Package version matching claim and BAD/GOOD JSON examples are correct + +--- + +#### 6. Wrong Retry Classification +**Status:** all good + +**Verified:** error examples, ApplicationFailure.create() without nonRetryable, .nonRetryable() API, error-handling.md reference all correct + +--- + +#### 7. Cancellation - Not Handling Workflow +**Status:** all good + +**Verified:** CancellationScope import, .nonCancellable() for cleanup, try/finally pattern all correct + +--- + +#### 7b. Cancellation - Not Handling Activity +**Status:** FIXED + +**SDK team feedback:** Original section was only about workflow cleanup, missing the important case of activity cancellation handling. Activities must opt in to receive cancellation via: +1. Heartbeating (cancellation is delivered via heartbeat) +2. Checking for cancellation via `Context.current().cancelled` promise or `cancellationSignal()` AbortSignal + +**Added content:** +- `Context.current().cancelled` - Promise that rejects with CancelledFailure +- `cancellationSignal()` - AbortSignal for use with fetch, child_process, etc. +- Note about Promise.race not stopping the losing promise + +**Key guidance (apply to all languages):** +- Activities that don't heartbeat won't know they've been cancelled +- Two approaches: await cancelled promise, or use AbortSignal with compatible libraries + +--- + +#### 8. Heartbeating - Forgetting to Heartbeat +**Status:** all good + +**Verified:** heartbeat import, heartbeat(details) API, progress reporting pattern all correct + +--- + +#### 9. Heartbeating - Timeout Too Short +**Status:** all good + +**Verified:** heartbeatTimeout in proxyActivities and timeout guidance correct + +--- + +#### 10. Testing - Not Testing Failures +**Status:** all good + +**Verified:** createTimeSkipping(), nativeConnection, runUntil(), ApplicationFailure.nonRetryable() all correct + +--- + +#### 11. Testing - Not Testing Replay +**Status:** FIXED + +**Fixed:** Updated history loading to use fs.promises.readFile pattern for clarity. + +--- + +#### 12. Timers and Sleep +**Status:** all good + +**Verified:** setTimeout BAD pattern, sleep import, duration string format, durability claim all correct + +--- + + +## Python + +**File:** `references/python/gotchas.md` (relative to skill root) + +### Tracking + +| # | Section | Status | Fix Applied | Sources | +|---|---------|--------|-------------|---------| +| 1 | File Organization (intro) | needs fixes | | context7 sdk-python | +| 2 | File Organization | needs fixes | | context7 sdk-python | +| 3 | Importing Activities into Workflow Files | needs fixes | | context7 sdk-python | +| 4 | Mixing Workflows and Activities | needs fixes | | context7 sdk-python | +| 5 | Async vs Sync Activities | needs fixes | | context7 sdk-python | +| 6 | Blocking in Async Activities | all good | | context7 sdk-python | +| 7 | Missing Executor for Sync Activities | needs fixes | | context7 sdk-python | +| 8 | Wrong Retry Classification | all good | | context7 sdk-python | +| 9 | Heartbeating | all good | | context7 sdk-python | +| 10 | Cancellation - Not Handling Workflow | FIXED | Added workflow cancellation section | SDK team feedback | +| 11 | Cancellation - Not Handling Activity | FIXED | Added activity cancellation section | SDK team feedback | +| 12 | Testing / Timers and Sleep | needs fixes | | context7 sdk-python | + +### Detailed Notes + +#### 1. File Organization (intro) +**Status:** needs fixes + +**Issues:** +- **Inaccurate claim:** "The Python sandbox reloads workflow files on every task" +- **Correct:** "The Python sandbox reloads non-standard-library and non-Temporal modules for each workflow run" +- Task vs workflow run is important distinction +- Standard library and Temporal SDK modules are passed through (not re-imported) + +--- + +#### 2. File Organization +**Status:** needs fixes + +**Issues:** +- Same inaccuracy as §1 - says "workflow files" but should say "non-standard-library modules" +- The `imports_passed_through()` pattern itself is correct ✓ +- Missing context: should mention performance AND memory benefits, not just "slows down workers" + +--- + +#### 3. Importing Activities into Workflow Files +**Status:** needs fixes + +**Issues:** +- **Inaccurate:** "on every task" should be "for each workflow run or replay" +- The `workflow.unsafe.imports_passed_through()` pattern is correct ✓ +- SDK docs: "re-imports the workflow definition file into a new sandbox environment for each workflow run or replay" + +--- + +#### 4. Mixing Workflows and Activities +**Status:** needs fixes + +**Issues:** +- Recommendation to separate files is correct ✓ +- **Missing:** Primary documented reason is testability, not just performance +- **Incomplete:** The "GOOD" example shows `my_activity` referenced but never imported +- Should show complete pattern with `imports_passed_through()` for activity import +- Or reference §3 which covers the import pattern + +--- + +#### 5. Async vs Sync Activities +**Status:** needs fixes + +**Issues:** +- All technical claims about async vs sync activities are correct ✓ +- **Typo:** Line 66 says "aysnc" should be "async" +- Blocking warning and executor requirement correctly documented ✓ + +--- + +#### 6. Blocking in Async Activities +**Status:** all good + +**Verified:** +- Blocking I/O in async activity is BAD ✓ +- SDK docs: "WARNING: Do not block the thread in `async def` Python functions" +- GOOD Option 1: sync activity with `ThreadPoolExecutor` ✓ +- GOOD Option 2: async I/O with `aiofiles` ✓ + +--- + +#### 7. Missing Executor for Sync Activities +**Status:** needs fixes + +**Issues:** +- Core claim is correct: sync activities REQUIRE executor ✓ +- **Claim unverified:** "THIS IMMEDIATELY RAISES AN EXCEPTION!" +- SDK docs say executor "must be set" but don't specify exact error behavior +- The requirement is documented, but the timing/nature of error is not explicitly stated +- **Recommendation:** Soften to "Sync activities require an executor" without specific exception claim + +--- + +#### 8. Wrong Retry Classification +**Status:** all good + +**Verified:** +- Concept is accurate ✓ +- Reference to `references/python/error-handling.md` path is correct ✓ + +--- + +#### 9. Heartbeating +**Status:** all good + +**Verified:** +- `activity.heartbeat(details)` API ✓ +- Progress reporting pattern ✓ +- `heartbeat_timeout` parameter in `workflow.execute_activity()` ✓ +- Guidance on appropriate timeout values ✓ +- SDK docs: "It is strongly recommended that all but the fastest executing activities call this function regularly" + +--- + +#### 10. Cancellation - Not Handling Workflow +**Status:** FIXED + +**SDK team feedback:** Added workflow cancellation section (parallel to TypeScript). Shows try/finally pattern to ensure cleanup runs on cancellation. + +--- + +#### 11. Cancellation - Not Handling Activity +**Status:** FIXED + +**SDK team feedback:** Added activity cancellation handling section (parallel to TypeScript). Activities must opt in to receive cancellation via: +1. Heartbeating (cancellation is delivered via heartbeat) +2. Checking `activity.is_cancelled()` or catching cancellation exception + +**Key differences from TypeScript:** +- No `cancellationSignal()` equivalent in Python +- Exception types differ: `asyncio.CancelledError` (async) vs `temporalio.exceptions.CancelledError` (sync threaded) + +--- + +#### 12. Testing / Timers and Sleep +**Status:** needs fixes + +**Issues:** +- **MAJOR ERROR:** Document claims `asyncio.sleep` is "Non-deterministic!" in workflows +- **This is INCORRECT** - In Temporal Python workflows, `asyncio.sleep` IS backed by workflow timers +- SDK docs: "Timers in Temporal workflows are typically implemented using `asyncio.sleep()` or `workflow.sleep()`" +- SDK example shows: `await asyncio.sleep(24 * 60 * 60)` in a workflow +- Both `asyncio.sleep()` and `workflow.sleep()` create deterministic timers in workflows +- `workflow.sleep()` accepts `timedelta` or string durations, `asyncio.sleep()` accepts numeric seconds +- **Recommendation:** Remove the BAD/GOOD framing - both are valid + +--- + + +## Go + +**File:** `references/go/gotchas.md` (relative to skill root) + +### Tracking + +| # | Section | Status | Fix Applied | Sources | +|---|---------|--------|-------------|---------| +| 1 | Goroutines and Concurrency | all good | | temporal-docs | +| 2 | Non-Deterministic Operations | FIXED | Used `encoded.Get(&r)` pattern for SideEffect | temporal-docs | +| 3 | Wrong Retry Classification | all good | | temporal-docs | +| 4 | Cancellation | all good | | temporal-docs | +| 5 | Heartbeating | all good | | temporal-docs | +| 6 | Testing | all good | | temporal-docs | +| 7 | Timers and Sleep | all good | | temporal-docs | + +### Detailed Notes + +#### 1. Goroutines and Concurrency +**Status:** all good +**Verified:** +- Native `go`, `chan`, `select` flagged as non-deterministic ✓ +- `workflow.Go`, `workflow.NewChannel`, `workflow.NewSelector` as safe alternatives ✓ + +--- + +#### 2. Non-Deterministic Operations +**Status:** FIXED + +**Issue:** `workflow.SideEffect` is shown with tuple destructuring `val, _ := workflow.SideEffect(ctx, func(ctx workflow.Context) interface{} { ... })` but `workflow.SideEffect` returns a single `converter.EncodedValue`, not a tuple. Must use `.Get(&variable)` to extract the value. Code as written will not compile. + +**Correct pattern:** +```go +encodedVal := workflow.SideEffect(ctx, func(ctx workflow.Context) interface{} { + return rand.Intn(100) +}) +var val int +_ = encodedVal.Get(&val) +``` + +--- + +#### 3. Wrong Retry Classification +**Status:** all good +**Verified:** +- `temporal.NewApplicationError` for retryable errors ✓ +- `temporal.NewNonRetryableApplicationError` for permanent errors ✓ + +--- + +#### 4. Cancellation +**Status:** all good +**Verified:** +- `workflow.NewDisconnectedContext` for cleanup ✓ +- Activity cancellation via heartbeat ✓ + +--- + +#### 5. Heartbeating +**Status:** all good +**Verified:** +- `activity.RecordHeartbeat` API ✓ +- `HeartbeatTimeout` configuration ✓ + +--- + +#### 6. Testing +**Status:** all good +**Verified:** +- Testing patterns referenced correctly ✓ + +--- + +#### 7. Timers and Sleep +**Status:** all good +**Verified:** +- `time.Sleep` flagged as non-deterministic ✓ +- `workflow.Sleep` as safe alternative ✓ + +--- + diff --git a/.memory/correctness_checking/language.md b/.memory/correctness_checking/language.md new file mode 100644 index 0000000..7707133 --- /dev/null +++ b/.memory/correctness_checking/language.md @@ -0,0 +1,297 @@ +# {language}.md (top-level files) + +Correctness verification for `references/{language}/{language}.md` (e.g., typescript.md, python.md). + +## TypeScript + +**File:** `references/typescript/typescript.md` (relative to skill root) + +### Tracking + +| # | Section | Status | Fix Applied | Sources | +|---|---------|--------|-------------|---------| +| 1 | Overview | FIXED | Changed to "isolated runtime with bundling" | context7 sdk-typescript | +| 2 | Understanding Replay | FIXED | Fixed ref path to references/core/ | context7 sdk-typescript | +| 3 | Quick Start | FIXED | Package-manager agnostic (removed `npm install` command) | SDK team feedback | +| 4 | Key Concepts | FIXED | Added defineUpdate() and activities param | context7 sdk-typescript | +| 5 | File Organization Best Practice | all good | | context7 sdk-typescript | +| 6 | Determinism Rules | all good | | context7 sdk-typescript | +| 7 | Common Pitfalls | FIXED | Updated logging: prefer `log`, but console.log works (patched) | SDK team feedback | +| 8 | Writing Tests | all good | | context7 sdk-typescript | +| 9 | Additional Resources | all good | | context7 sdk-typescript | + +### Detailed Notes + +#### 1. Overview +**Status:** FIXED + +**Fixed:** Changed "V8 sandbox" to "isolated runtime with bundling and automatic replacements". + +--- + +#### 2. Understanding Replay +**Status:** FIXED + +**Fixed:** Changed ref path from `core/determinism.md` to `references/core/determinism.md`. + +--- + +#### 3. Quick Start +**Status:** FIXED + +**SDK team feedback:** Users may use different package managers (npm, pnpm, yarn, bun). Removed specific `npm install` command, now just lists the packages to install. + +**Verified:** Code examples (activities.ts, workflows.ts, worker.ts, client.ts), commands, expected output all correct + +--- + +#### 4. Key Concepts +**Status:** FIXED + +**Fixed:** Added `defineUpdate()` to Workflow Definition, added `activities` parameter to Worker Setup. + +--- + +#### 5. File Organization Best Practice +**Status:** all good + +**Verified:** Bundling performance claim, directory structure, type-only import pattern all correct + +--- + +#### 6. Determinism Rules +**Status:** all good + +**Verified:** Math.random(), Date.now(), setTimeout replacements are accurate. sleep() and condition() as safe alternatives is correct. + +--- + +#### 7. Common Pitfalls +**Status:** FIXED + +**SDK team feedback:** `console.log` is NOT forbidden - the SDK patches console.log/warn/error to include workflow ID. Updated to say "Prefer `log` from `@temporalio/workflow`" and note that "console.log also works (it's patched to include workflow ID)". + +--- + +#### 8. Writing Tests +**Status:** all good + +**Verified:** Reference path to testing.md is correct + +--- + +#### 9. Additional Resources +**Status:** all good + +**Verified:** All 10 reference file paths exist and are correct + +--- + + +## Python + +**File:** `references/python/python.md` (relative to skill root) + +### Tracking + +| # | Section | Status | Fix Applied | Sources | +|---|---------|--------|-------------|---------| +| 1 | Overview | needs fixes | | context7 sdk-python | +| 2 | Quick Demo of Temporal | all good | | context7 sdk-python | +| 3 | Key Concepts - Workflow Definition | all good | | context7 sdk-python | +| 4 | Key Concepts - Activity Definition | all good | | context7 sdk-python | +| 5 | Key Concepts - Worker Setup | all good | | context7 sdk-python | +| 6 | Key Concepts - Determinism | all good | | file verification | +| 7 | File Organization Best Practice | needs fixes | | context7 sdk-python | +| 8 | Common Pitfalls | needs fixes | | context7 sdk-python | +| 9 | Writing Tests | all good | | file verification | +| 10 | Additional Resources | all good | | file verification | + +### Detailed Notes + +#### 1. Overview +**Status:** needs fixes + +**Issues:** +- "Fully async, type-safe" description ✓ +- **"Python 3.9+ required" is OUTDATED** - SDK v1.22.0 requires **Python 3.10+** +- "Sandbox by default for determinism protection" ✓ + +--- + +#### 2. Quick Demo of Temporal +**Status:** all good + +**Verified:** +- `temporalio` package name ✓ +- `@activity.defn` decorator on sync function ✓ +- `@workflow.defn` on class, `@workflow.run` on method ✓ +- `workflow.unsafe.imports_passed_through()` for activity import ✓ +- `workflow.execute_activity(fn, arg, start_to_close_timeout=...)` API ✓ +- `Client.connect()`, `Worker()` constructor, `worker.run()` pattern ✓ +- `ThreadPoolExecutor` for sync activity executor ✓ +- `workflows=[...]` and `activities=[...]` parameters ✓ +- `client.execute_workflow(Workflow.run, arg, id=..., task_queue=...)` API ✓ +- `temporal server start-dev` command ✓ +- Expected output "Result: Hello, my-name!" ✓ + +--- + +#### 3. Key Concepts - Workflow Definition +**Status:** all good + +**Verified:** +- `@workflow.defn` decorator on class ✓ +- `@workflow.run` on entry point method ✓ +- Must be async (`async def`) ✓ +- `@workflow.signal`, `@workflow.query`, `@workflow.update` decorators ✓ +- SDK docs: "The decorated method must be an `async def` function" + +--- + +#### 4. Key Concepts - Activity Definition +**Status:** all good + +**Verified:** +- `@activity.defn` decorator ✓ +- Can be sync or async functions ✓ +- "Default to sync activities" recommendation matches official guidance ✓ +- Sync activities need `activity_executor` (ThreadPoolExecutor) ✓ +- Async activities require async-safe libraries ✓ +- Reference to `sync-vs-async.md` path exists ✓ + +--- + +#### 5. Key Concepts - Worker Setup +**Status:** all good + +**Verified:** +- Connect client, create Worker pattern ✓ +- `await worker.run()` method ✓ +- Custom executor via `activity_executor` parameter ✓ + +--- + +#### 6. Key Concepts - Determinism +**Status:** all good + +**Verified:** +- "Workflow code must be deterministic" claim ✓ +- Both reference files exist: + - `references/core/determinism.md` ✓ + - `references/python/determinism.md` ✓ + +--- + +#### 7. File Organization Best Practice +**Status:** needs fixes + +**Issues:** +- **Imprecise claim:** "Sandbox reloads Workflow definition files on every execution" +- **More accurate:** "Sandbox re-imports non-passthrough modules in Workflow files for each workflow run" +- SDK docs: "re-imports the workflow definition file into a new sandbox environment for each workflow run or replay" +- Standard library and passthrough modules are NOT reloaded +- Directory structure recommendation is valid ✓ +- Pass-through import pattern is correct ✓ + +--- + +#### 8. Common Pitfalls +**Status:** needs fixes + +**Issues:** +- Pitfalls 1-4, 6-7 are accurate ✓ +- **Pitfall 5 (gevent) needs refinement:** Says "Incompatible with SDK" but SDK docs note a workaround exists +- SDK docs: "This is a known incompatibility... But if you must, there is a sample showing how it is possible" +- Suggest: "gevent is problematic and discouraged, but possible with workarounds (see samples-python/gevent_async)" + +--- + +#### 9. Writing Tests +**Status:** all good + +**Verified:** +- Reference path `references/python/testing.md` exists ✓ + +--- + +#### 10. Additional Resources +**Status:** all good + +**Verified:** +- All 12 reference file paths exist ✓ + +--- + + +## Go + +**File:** `references/go/go.md` (relative to skill root) + +### Tracking + +| # | Section | Status | Fix Applied | Sources | +|---|---------|--------|-------------|---------| +| 1 | Overview | all good | | temporal-docs | +| 2 | Quick Start | all good | | temporal-docs | +| 3 | Key Concepts | all good | | temporal-docs | +| 4 | File Organization Best Practice | all good | | temporal-docs | +| 5 | Common Pitfalls | all good | | temporal-docs | +| 6 | Writing Tests | all good | | temporal-docs | +| 7 | Additional Resources | all good | | temporal-docs | + +### Detailed Notes + +#### 1. Overview +**Status:** all good +**Verified:** +- No runtime sandbox, developer-convention-based determinism ✓ +- `workflowcheck` static analysis tool mentioned ✓ + +--- + +#### 2. Quick Start +**Status:** all good +**Verified:** +- `go.temporal.io/sdk` dependency ✓ +- Workflow, activity, worker, client code examples ✓ + +--- + +#### 3. Key Concepts +**Status:** all good +**Verified:** +- Workflow as exported Go function ✓ +- Activity definition pattern ✓ +- Worker setup with `worker.New` ✓ + +--- + +#### 4. File Organization Best Practice +**Status:** all good +**Verified:** +- Recommended directory structure ✓ + +--- + +#### 5. Common Pitfalls +**Status:** all good +**Verified:** +- Determinism pitfalls listed accurately ✓ + +--- + +#### 6. Writing Tests +**Status:** all good +**Verified:** +- Reference to testing.md path ✓ + +--- + +#### 7. Additional Resources +**Status:** all good +**Verified:** +- Reference file paths listed correctly ✓ + +--- + diff --git a/.memory/correctness_checking/observability.md b/.memory/correctness_checking/observability.md new file mode 100644 index 0000000..2c7e4e0 --- /dev/null +++ b/.memory/correctness_checking/observability.md @@ -0,0 +1,255 @@ +# observability.md + +Correctness verification for `references/{language}/observability.md`. + +## TypeScript + +**File:** `references/typescript/observability.md` (relative to skill root) + +### Tracking + +| # | Section | Status | Fix Applied | Sources | +|---|---------|--------|-------------|---------| +| 1 | Overview | all good | | context7 sdk-typescript | +| 2 | Replay-Aware Logging - Workflow | FIXED | Clarified log export since SDK 1.8.0 | context7 sdk-typescript | +| 3 | Replay-Aware Logging - Activity | FIXED | Use log from @temporalio/activity | context7 sdk-typescript | +| 4 | Customizing the Logger - Basic | all good | | context7 sdk-typescript | +| 5 | Customizing the Logger - Winston | all good | | context7 sdk-typescript | +| 6 | Metrics - Prometheus | all good | | context7 sdk-typescript | +| 7 | Metrics - OTLP | all good | | context7 sdk-typescript | +| 8 | Best Practices | FIXED | Updated logging: prefer `log`, but console.log works (patched) | SDK team feedback | + +### Detailed Notes + +#### 1. Overview +**Status:** all good + +**Verified:** Replay-aware logging claim and metrics mention are correct + +--- + +#### 2. Replay-Aware Logging - Workflow +**Status:** FIXED + +**Fixed:** Clarified that `import { log } from '@temporalio/workflow'` is correct since SDK 1.8.0. + +--- + +#### 3. Replay-Aware Logging - Activity +**Status:** FIXED + +**Fixed:** Updated to use `import { log } from '@temporalio/activity'` with direct `log.info()` calls. + +--- + +#### 4. Customizing the Logger - Basic +**Status:** all good + +**Verified:** DefaultLogger, Runtime imports, constructor pattern, Runtime.install API all correct + +--- + +#### 5. Customizing the Logger - Winston +**Status:** all good + +**Verified:** Winston integration, entry properties (level, message, meta, timestampNanos), BigInt division all correct + +--- + +#### 6. Metrics - Prometheus +**Status:** all good + +**Verified:** Runtime.install with telemetryOptions.metrics.prometheus and bindAddress format correct + +--- + +#### 7. Metrics - OTLP +**Status:** all good + +**Verified:** telemetryOptions.metrics.otel configuration, url and metricsExportInterval options correct + +--- + +#### 8. Best Practices +**Status:** FIXED + +**SDK team feedback:** `console.log` is NOT forbidden - the SDK patches console.log/warn/error to include workflow ID. Updated best practice #1 to say "Prefer `log`" rather than implying console.log is wrong. + +**Verified:** All 6 best practices valid + +--- + + +## Python + +**File:** `references/python/observability.md` (relative to skill root) + +### Tracking + +| # | Section | Status | Fix Applied | Sources | +|---|---------|--------|-------------|---------| +| 1 | Overview | all good | | context7 sdk-python | +| 2 | Workflow Logging (Replay-Safe) | all good | | context7 sdk-python | +| 3 | Activity Logging | needs fixes | | context7 sdk-python, sdk source | +| 4 | Customizing Logger Configuration | needs fixes | | context7 sdk-python, sdk source | +| 5 | Enabling SDK Metrics | needs fixes | | context7 sdk-python, temporal-docs | +| 6 | Key SDK Metrics | all good | | temporal-docs | +| 7 | Search Attributes (Visibility) | needs fixes | | context7 sdk-python | +| 8 | Best Practices | needs fixes | | context7 sdk-python | + +### Detailed Notes + +#### 1. Overview +**Status:** all good + +**Verified:** +- Logging via `workflow.logger` and `activity.logger` ✓ +- Metrics via SDK metrics emission and custom metric meters ✓ +- Visibility (Search Attributes) for querying and filtering workflows ✓ + +--- + +#### 2. Workflow Logging (Replay-Safe) +**Status:** all good + +**Verified:** +- `workflow.logger` API ✓ +- `workflow.logger.info(message, extra={...})` signature ✓ +- "Suppresses duplicate logs during replay" - SDK confirms logger "skips logging during replay operations" ✓ +- Includes workflow context ✓ + +--- + +#### 3. Activity Logging +**Status:** needs fixes + +**Issues:** +- `activity.logger` API is correct ✓ +- **Incomplete context list:** Document says "Activity ID, type, and task queue; Workflow ID and run ID; Attempt number" +- **Actual SDK includes:** activity_id, activity_type, attempt, namespace, task_queue, workflow_id, workflow_run_id, workflow_type +- **Missing from doc:** `namespace` and `workflow_type` + +--- + +#### 4. Customizing Logger Configuration +**Status:** needs fixes + +**Issues:** +- `logging.basicConfig()` does affect Temporal loggers ✓ +- **Misleading comment:** "Temporal inherits the default logger" is incorrect +- Temporal loggers are named loggers (`temporalio.workflow`, `temporalio.activity`) that propagate to root +- Configuration works via **propagation**, not inheritance of default logger + +--- + +#### 5. Enabling SDK Metrics +**Status:** needs fixes + +**Issues:** +- All imports and API are correct ✓ +- `Runtime.set_default()` is technically valid ✓ +- **Non-standard approach:** Official docs and samples pass `runtime=` to `Client.connect()` instead +- Official pattern: `client = await Client.connect(..., runtime=runtime)` +- Document's approach works but diverges from canonical examples + +--- + +#### 6. Key SDK Metrics +**Status:** all good + +**Verified:** +- `temporal_request` - Client requests to server ✓ +- `temporal_workflow_task_execution_latency` - Workflow task processing time ✓ +- `temporal_activity_execution_latency` - Activity execution time ✓ +- `temporal_workflow_task_replay_latency` - Replay duration ✓ + +--- + +#### 7. Search Attributes (Visibility) +**Status:** needs fixes + +**Issues:** +- Reference to `data-handling.md` is correct ✓ +- **Same issue as data-handling.md §6:** `workflow.upsert_search_attributes()` API is incorrect +- Document shows: `workflow.upsert_search_attributes(TypedSearchAttributes([...]))` +- Correct API: `workflow.upsert_search_attributes([KEY.value_set(value)])` + +--- + +#### 8. Best Practices +**Status:** needs fixes + +**Issues:** +- Best practices #2-4 are valid ✓ +- **Best practice #1 is INCORRECT:** "`activity.logger` in activities" - `activity.logger` does NOT exist +- Activities can use standard Python logging or print statements +- Should say: "Use `workflow.logger` in workflows for replay-safe logging; activities can use standard Python logging" + +--- + + +## Go + +**File:** `references/go/observability.md` (relative to skill root) + +### Tracking + +| # | Section | Status | Fix Applied | Sources | +|---|---------|--------|-------------|---------| +| 1 | Overview | all good | | temporal-docs | +| 2 | Logging / Replay-Aware Logging | all good | | temporal-docs | +| 3 | Customizing the Logger | all good | | temporal-docs | +| 4 | Metrics | all good | | temporal-docs | +| 5 | Search Attributes (Visibility) | all good | | temporal-docs | +| 6 | Best Practices | all good | | temporal-docs | + +### Detailed Notes + +#### 1. Overview +**Status:** all good +**Verified:** +- `workflow.GetLogger` and `activity.GetLogger` APIs ✓ +- Tally library with Prometheus export ✓ +- OpenTelemetry/OpenTracing/Datadog tracing ✓ + +--- + +#### 2. Logging / Replay-Aware Logging +**Status:** all good +**Verified:** +- `workflow.GetLogger(ctx)` for replay-safe workflow logging ✓ +- `activity.GetLogger(ctx)` for activity logging ✓ + +--- + +#### 3. Customizing the Logger +**Status:** all good +**Verified:** +- `log.NewStructuredLogger` API ✓ +- Custom logger via `client.Options` ✓ + +--- + +#### 4. Metrics +**Status:** all good +**Verified:** +- `sdktally.NewMetricsHandler` API ✓ +- `client.Options{MetricsHandler}` configuration ✓ +- Prometheus export via Tally ✓ + +--- + +#### 5. Search Attributes (Visibility) +**Status:** all good +**Verified:** +- Search attribute reference ✓ + +--- + +#### 6. Best Practices +**Status:** all good +**Verified:** +- All best practices valid ✓ + +--- + diff --git a/.memory/correctness_checking/patterns.md b/.memory/correctness_checking/patterns.md new file mode 100644 index 0000000..1500eba --- /dev/null +++ b/.memory/correctness_checking/patterns.md @@ -0,0 +1,712 @@ +# patterns.md + +Correctness verification for `references/{language}/patterns.md`. + +## TypeScript + +**File:** `references/typescript/patterns.md` (relative to skill root) + +### Tracking + +| # | Section | Status | Fix Applied | Sources | +|---|---------|--------|-------------|---------| +| 1 | Signals | all good | | context7 sdk-typescript, temporal-docs | +| 2 | Dynamic Signal Handlers | FIXED | Used `setDefaultSignalHandler` | context7 sdk-typescript, temporal-docs | +| 3 | Queries | all good | Added "Important" note during alignment | context7 sdk-typescript, temporal-docs | +| 4 | Dynamic Query Handlers | FIXED | Used `setDefaultQueryHandler` | temporal-docs | +| 5 | Updates | all good | | context7 sdk-typescript, temporal-docs | +| 6 | Child Workflows | all good | | context7 sdk-typescript, temporal-docs | +| 7 | Child Workflow Options | all good | | context7 sdk-typescript, temporal-docs | +| 8 | Handles to External Workflows | all good | | context7 sdk-typescript | +| 9 | Parallel Execution | all good | | context7 sdk-typescript | +| 10 | Continue-as-New | all good | | context7 sdk-typescript | +| 11 | Saga Pattern | FIXED | Wrap compensations in CancellationScope.nonCancellable(); move registration before activity call | temporal-docs | +| 12 | Cancellation Scopes | all good | | context7 sdk-typescript, temporal-docs | +| 13 | Triggers (Promise-like Signals) | all good | | temporal-docs api reference | +| 14 | Wait Condition with Timeout | all good | | context7 sdk-typescript, temporal-docs | +| 15 | Waiting for All Handlers to Finish | FIXED | Simplified; added context about non-async handler preference | SDK team feedback, temporal-docs | +| 16 | Activity Heartbeat Details | all good | | context7 sdk-typescript, temporal-docs | +| 17 | Timers | all good | | context7 sdk-typescript | +| 18 | Local Activities | FIXED | Wrong import: `executeLocalActivity` → `proxyLocalActivities` | context7 sdk-typescript | + +### Detailed Notes + +#### 1. Signals +**Status:** all good + +**Verified:** +- `defineSignal`, `setHandler`, `condition` imports from `@temporalio/workflow` ✓ +- `defineSignal<[boolean]>('approve')` syntax with type parameter as array of arg types ✓ +- `setHandler(signal, handler)` pattern ✓ +- `await condition(() => approved)` for waiting on state ✓ + +--- + +#### 2. Dynamic Signal Handlers +**Status:** FIXED + +**Issue:** The current code uses a non-existent predicate-based `setHandler` API. The TypeScript SDK uses `setDefaultSignalHandler` for handling signals with unknown names. + +**Before:** +```typescript +setHandler( + (signalName: string) => true, // This API doesn't exist + (signalName: string, ...args: unknown[]) => { ... } +); +``` + +**After:** +```typescript +import { setDefaultSignalHandler, condition } from '@temporalio/workflow'; + +export async function dynamicSignalWorkflow(): Promise> { + const signals: Record = {}; + + setDefaultSignalHandler((signalName: string, ...args: unknown[]) => { + if (!signals[signalName]) { + signals[signalName] = []; + } + signals[signalName].push(args); + }); + + await condition(() => signals['done'] !== undefined); + return signals; +} +``` + +**Source:** https://typescript.temporal.io/api/namespaces/workflow#setdefaultsignalhandler + +--- + +#### 3. Queries +**Status:** all good + +**Verified:** +- `defineQuery`, `setHandler` imports from `@temporalio/workflow` ✓ +- `defineQuery('status')` - return type as type parameter ✓ +- `setHandler(query, () => value)` - synchronous handler returning value ✓ +- Query handlers must be synchronous (not async) ✓ +- **Important note verified**: "Queries must NOT modify workflow state or have side effects" ✓ + - temporal-docs: "Queries are _read-only_ and must complete synchronously" + - temporal-docs: "A Query handler returns a value: it must not mutate the Workflow state" + +--- + +#### 4. Dynamic Query Handlers +**Status:** FIXED + +**Issue:** Same as Dynamic Signal Handlers - uses non-existent predicate-based API. + +**Correct API:** `setDefaultQueryHandler` + +```typescript +setDefaultQueryHandler((queryName: string, ...args: any[]) => { + // return value +}); +``` + +**Source:** https://typescript.temporal.io/api/namespaces/workflow#setdefaultqueryhandler + +--- + +#### 5. Updates +**Status:** all good + +**Verified:** +- `defineUpdate('name')` syntax - return type first, then args as tuple type ✓ +- `setHandler(update, handler, { validator })` pattern matches official docs ✓ +- Validator is synchronous, throws error to reject ✓ +- Handler can be sync or async, returns a value ✓ +- Imports `defineUpdate`, `setHandler`, `condition` from `@temporalio/workflow` ✓ + +--- + +#### 6. Child Workflows +**Status:** all good + +**Verified:** +- `executeChild` import from `@temporalio/workflow` ✓ +- `executeChild(workflowFunc, { args, workflowId })` syntax correct ✓ +- Child scheduled on same task queue as parent by default ✓ + +--- + +#### 7. Child Workflow Options +**Status:** all good + +**Verified:** +- `ParentClosePolicy` values: `TERMINATE` (default), `ABANDON`, `REQUEST_CANCEL` ✓ +- `ChildWorkflowCancellationType` values: `WAIT_CANCELLATION_COMPLETED` (default), `WAIT_CANCELLATION_REQUESTED`, `TRY_CANCEL`, `ABANDON` ✓ +- Both imported from `@temporalio/workflow` ✓ + +--- + +#### 8. Handles to External Workflows +**Status:** all good + +**Verified:** +- `getExternalWorkflowHandle(workflowId)` from `@temporalio/workflow` ✓ +- Synchronous function (not async) ✓ +- `handle.signal()` and `handle.cancel()` methods exist ✓ + +--- + +#### 9. Parallel Execution +**Status:** all good + +**Verified:** +- `Promise.all` for parallel execution is standard pattern ✓ +- Used in official examples for parallel child workflows ✓ + +--- + +#### 10. Continue-as-New +**Status:** all good + +**Verified:** +- `continueAsNew`, `workflowInfo` imports from `@temporalio/workflow` ✓ +- `await continueAsNew(args)` syntax correct ✓ +- `workflowInfo().continueAsNewSuggested` property exists ✓ +- Checking history length threshold is standard pattern ✓ + +--- + +#### 11. Saga Pattern +**Status:** FIXED + +**Verified:** +- Array of compensation functions pattern ✓ +- No built-in Saga class in TS SDK (unlike Java), manual implementation correct ✓ +- Idempotency note ✓ +- Replay-safe logging `import { log } from '@temporalio/workflow'` ✓ + +**Issues fixed:** +- **Compensations must run in `CancellationScope.nonCancellable()`**: When the workflow is cancelled, any new activity scheduled in the root scope throws `CancelledFailure` immediately before starting. Official docs: "Cleanup logic must be in a nonCancellable scope — If we'd run cleanup outside of a nonCancellable scope it would've been cancelled before being started because the Workflow's root scope is cancelled." (docs.temporal.io/develop/typescript/cancellation#external-cancellation-example) +- **Compensation registration order was wrong**: Compensations were pushed *after* calling the activity. Must be registered *before* the activity call. + +**Fix applied:** Wrapped compensation loop in `CancellationScope.nonCancellable(async () => { ... })` and moved `compensations.push(...)` before each activity call. + - docs.temporal.io: "This logger is replay-aware and will omit log messages on workflow replay" + - edu-102-typescript: "import `log` from `@temporalio/workflow` to access the Workflow Logger" + +--- + +#### 12. Cancellation Scopes +**Status:** all good + +**Verified:** +- `CancellationScope` from `@temporalio/workflow` ✓ +- `CancellationScope.nonCancellable(fn)` - prevents cancellation propagation ✓ +- `CancellationScope.withTimeout(timeout, fn)` - auto-cancels after timeout ✓ +- `new CancellationScope()` + `scope.run(fn)` + `scope.cancel()` pattern ✓ + +--- + +#### 13. Triggers (Promise-like Signals) +**Status:** all good + +**Verified:** +- `Trigger` class from `@temporalio/workflow` ✓ +- `new Trigger()` creates a PromiseLike that exposes resolve/reject ✓ +- `trigger.resolve(value)` to resolve from signal handler ✓ +- `await trigger` works because Trigger implements PromiseLike ✓ +- CancellationScope-aware (throws when scope cancelled) ✓ + +--- + +#### 14. Wait Condition with Timeout +**Status:** all good + +**Verified:** +- `condition(fn, timeout)` with timeout returns `Promise` ✓ +- Returns `true` if condition met, `false` if timeout expires ✓ +- String duration format `'24 hours'` supported (ms-formatted string) ✓ +- Import of `CancelledFailure` unused in example but harmless ✓ + +--- + +#### 15. Waiting for All Handlers to Finish +**Status:** FIXED + +**Issue 1:** Current code used overly complex condition with `workflowInfo().unsafe.isReplaying` and was missing import of `allHandlersFinished`. + +**Issue 2 (SDK team feedback):** Section was missing important context about when this pattern is needed. + +**Key guidance (apply to all languages):** +- Signal/update handlers should generally be non-async (avoid running activities from them) +- Otherwise, the workflow may complete before handlers finish +- Making handlers non-async sometimes requires workarounds that add complexity +- This pattern (`allHandlersFinished`) is for cases where async handlers are necessary + +**After:** +```typescript +import { condition, allHandlersFinished } from '@temporalio/workflow'; +// ... +await condition(allHandlersFinished); +``` + +**Source:** SDK team feedback, https://typescript.temporal.io/api/namespaces/workflow#allhandlersfinished + +**Notes:** +- `allHandlersFinished` is a function that returns `boolean` +- Pass it directly to `condition()` (not wrapped in a lambda) +- Official pattern: `await wf.condition(wf.allHandlersFinished)` + +--- + +#### 16. Activity Heartbeat Details +**Status:** FIXED + +**Verified:** +- `heartbeat`, `activityInfo` imports from `@temporalio/activity` ✓ +- `activityInfo().heartbeatDetails` gets heartbeat from previous failed attempt ✓ +- `heartbeat(details)` records checkpoint for resume ✓ +- Pattern matches official samples-typescript/activities-cancellation-heartbeating ✓ + +**SDK team feedback (apply to all languages):** +- **Most important use case is activity cancellation support** - cancellations are delivered to activities via heartbeat +- Activities that don't heartbeat cannot receive or respond to cancellation +- If activity is cancelled, `heartbeat()` throws `CancelledFailure` (TypeScript) +- Updated WHY/WHEN sections to emphasize cancellation as primary purpose +- Source: SDK team PR review, temporal-docs ("Activity Cancellations are delivered to Activities from the Temporal Service when they Heartbeat") + +**Notes:** +- `activityInfo()` is convenience function for `Context.current().info` +- heartbeatDetails can be any serializable value (number, object, etc.) + +--- + +#### 17. Timers +**Status:** all good + +**Verified:** +- `sleep` from `@temporalio/workflow` accepts duration strings ✓ +- `CancellationScope` for cancellable timers ✓ +- `scope.run()` and `scope.cancel()` pattern ✓ + +**Notes:** +- Example uses `setHandler` and `cancelSignal` without imports (pattern demonstration) + +--- + +#### 18. Local Activities +**Status:** FIXED + +**Issue:** Wrong import - code imported `executeLocalActivity` but used `proxyLocalActivities`. + +**Before:** +```typescript +import { executeLocalActivity } from '@temporalio/workflow'; +``` + +**After:** +```typescript +import { proxyLocalActivities } from '@temporalio/workflow'; +``` + +**Source:** context7 sdk-typescript documentation + +--- + +## Python + +**File:** `references/python/patterns.md` (relative to skill root) + +### Tracking + +| # | Section | Status | Fix Applied | Sources | +|---|---------|--------|-------------|---------| +| 1 | Signals | needs fixes | | context7 sdk-python | +| 2 | Dynamic Signal Handlers | all good | | context7 sdk-python | +| 3 | Queries | needs fixes | | context7 sdk-python | +| 4 | Dynamic Query Handlers | needs fixes | | context7 sdk-python | +| 5 | Updates | all good | | context7 sdk-python | +| 6 | Child Workflows | all good | | context7 sdk-python, temporal-docs | +| 7 | Handles to External Workflows | all good | | context7 sdk-python | +| 8 | Parallel Execution | needs fixes | | context7 sdk-python, sdk source | +| 9 | Deterministic Alternatives to asyncio | needs fixes | | context7 sdk-python, sdk source | +| 10 | Continue-as-New | needs fixes | | context7 sdk-python, temporal-docs | +| 11 | Saga Pattern | FIXED | Wrap compensations in asyncio.shield(); existing registration order was already correct | temporal-docs | +| 12 | Cancellation Handling | needs fixes | | context7 sdk-python | +| 13 | Wait Condition with Timeout | all good | | context7 sdk-python | +| 14 | Waiting for All Handlers to Finish | FIXED | Added context about non-async handler preference | SDK team feedback, context7 sdk-python | +| 15 | Activity Heartbeat Details | all good | | context7 sdk-python | +| 16 | Timers | all good | | context7 sdk-python | +| 17 | Local Activities | all good | | context7 sdk-python, temporal-docs | +| 18 | Using Pydantic Models | all good | | file verification | + +### Detailed Notes + +#### 1. Signals +**Status:** needs fixes + +**Issues:** +- Basic signal pattern (`@workflow.signal`, async handler, state modification) all correct ✓ +- `workflow.wait_condition(lambda: condition)` API correct ✓ +- **Needs verification:** `workflow.payload_converter().from_payload()` in dynamic handler example +- SDK docs show `activity.payload_converter()` for activities but workflow equivalent needs confirmation + +--- + +#### 2. Dynamic Signal Handlers +**Status:** all good + +**Verified:** +- `@workflow.signal(dynamic=True)` decorator ✓ +- Handler signature `(self, name: str, args: Sequence[RawValue])` ✓ +- `workflow.payload_converter().from_payload(args[0])` pattern consistent with SDK examples ✓ + +--- + +#### 3. Queries +**Status:** needs fixes + +**Issues:** +- `@workflow.query` decorator correct ✓ +- Non-async query handlers shown correctly ✓ +- "Queries must NOT modify workflow state" correctly stated ✓ +- **Missing:** Should explicitly state "Query methods should NOT be `async`" +- SDK docs: "Query methods should return a value and should not be `async`" + +--- + +#### 4. Dynamic Query Handlers +**Status:** needs fixes + +**Issues:** +- `@workflow.query(dynamic=True)` correct ✓ +- **Inconsistency in SDK docs:** SDK README says queries have "same semantics as signals" (requiring `Sequence[RawValue]`) +- But SDK README example shows simpler signature: `def get_dynamic_info(self, query_name: str) -> any:` +- Document uses full signature which is defensible but may not match simplest official example + +--- + +#### 5. Updates +**Status:** all good + +**Verified:** +- `@workflow.update` decorator ✓ +- Async update handler can modify state and return value ✓ +- `@update_handler.validator` decorator pattern ✓ +- Validator not async, returns None, raises to reject ✓ + +--- + +#### 6. Child Workflows +**Status:** all good + +**Verified:** +- `workflow.execute_child_workflow()` API ✓ +- First arg is workflow method reference ✓ +- `id` parameter is required for child workflows ✓ +- `parent_close_policy=workflow.ParentClosePolicy.ABANDON` ✓ + +--- + +#### 7. Handles to External Workflows +**Status:** all good + +**Verified:** +- `workflow.get_external_workflow_handle(workflow_id)` API ✓ +- `await handle.signal(TargetWorkflow.method, data)` ✓ +- `await handle.cancel()` ✓ + +--- + +#### 8. Parallel Execution +**Status:** needs fixes + +**Issues:** +- `asyncio.gather(*tasks)` for parallel activities ✓ +- **INCORRECT:** `workflow.WaitConditionResult.FIRST_COMPLETED` does NOT exist +- SDK source shows `return_when` is a string parameter accepting `asyncio.FIRST_COMPLETED` +- Correct: `workflow.wait(futures, return_when=asyncio.FIRST_COMPLETED)` + +--- + +#### 9. Deterministic Alternatives to asyncio +**Status:** needs fixes + +**Issues:** +- `workflow.wait()` and `workflow.as_completed()` exist ✓ +- **Same issue as §8:** `workflow.WaitConditionResult` enum does NOT exist +- `return_when` accepts standard asyncio constants: `asyncio.FIRST_COMPLETED`, `asyncio.FIRST_EXCEPTION`, `asyncio.ALL_COMPLETED` + +--- + +#### 10. Continue-as-New +**Status:** needs fixes + +**Issues:** +- `workflow.info().is_continue_as_new_suggested()` API correct ✓ +- "Fresh history before hitting limits" explanation correct ✓ +- **Non-idiomatic:** `workflow.continue_as_new(args=[state])` uses `args` (plural) +- Official docs pass single arg directly: `workflow.continue_as_new(state)` +- Or use `arg=state` (singular) for single argument + +--- + +#### 11. Saga Pattern +**Status:** FIXED + +**Verified:** +- Compensation list pattern correct ✓ +- `reversed(compensations)` for LIFO correct ✓ +- "Save compensation BEFORE running activity" correct and well-explained ✓ +- Idempotent compensation naming convention correct ✓ + +**Issues fixed:** +- **Compensations must run under `asyncio.shield()`**: When the workflow is cancelled, Python propagates `CancelledError` into the coroutine. Activities scheduled in the `except` block without shielding will also receive cancellation and may not run. Official Temporal blog (compensating-actions-part-of-a-complete-breakfast-with-sagas) uses `asyncio.shield(asyncio.ensure_future(...))` with comment "Ensure the compensations run in the face of cancellation." + +**Fix applied:** Wrapped compensation loop in `await asyncio.shield(asyncio.ensure_future(run_compensations()))`. + +**Still outstanding:** `ship_order` has no compensation registered — minor, acceptable if shipping is treated as a terminal action. + +--- + +#### 12. Cancellation Handling +**Status:** needs fixes + +**Issues:** +- `asyncio.CancelledError` for cancellation detection ✓ +- Re-raise `CancelledError` to mark workflow as cancelled ✓ +- **Misleading comment:** "Cleanup activities still run even after cancellation" +- SDK docs: Activities executed after catching CancelledError will also receive cancellation requests +- Should use `asyncio.shield()` to protect cleanup activities, or correct the comment + +--- + +#### 13. Wait Condition with Timeout +**Status:** all good + +**Verified:** +- `workflow.wait_condition(lambda: cond, timeout=timedelta(...))` API ✓ +- `asyncio.TimeoutError` on timeout expiry ✓ +- Pattern matches official SDK examples ✓ + +--- + +#### 14. Waiting for All Handlers to Finish +**Status:** FIXED + +**Verified:** +- `workflow.all_handlers_finished` function exists ✓ +- `workflow.wait_condition(workflow.all_handlers_finished)` pattern is correct ✓ +- Use cases: async handlers, before continue-as-new ✓ +- SDK docs: "One way to ensure that handler tasks have finished is to wait on the `workflow.all_handlers_finished` condition" + +**SDK team feedback (apply to all languages):** +- Signal/update handlers should generally be non-async (avoid running activities from them) +- Otherwise, the workflow may complete before handlers finish +- Making handlers non-async sometimes requires workarounds that add complexity +- This pattern is for cases where async handlers are necessary +- Added explanatory context to section + +--- + +#### 15. Activity Heartbeat Details +**Status:** FIXED + +**Verified:** +- `activity.info().heartbeat_details` returns iterable (indexable) ✓ +- `activity.heartbeat(progress)` API with `*details` signature ✓ +- Resume pattern: check heartbeat_details, skip processed items ✓ +- SDK docs: "If an activity calls `temporalio.activity.heartbeat(123, 456)` and then fails and is retried, `temporalio.activity.info().heartbeat_details` will return an iterable containing `123` and `456` on the next run." + +**SDK team feedback (apply to all languages):** +- **Most important use case is activity cancellation support** - cancellations are delivered to activities via heartbeat +- Activities that don't heartbeat cannot receive or respond to cancellation +- If activity is cancelled, `heartbeat()` raises `asyncio.CancelledError` (async) or `temporalio.exceptions.CancelledError` (sync threaded) +- Updated WHY/WHEN sections to emphasize cancellation as primary purpose +- Source: SDK team PR review, temporal-docs ("Activity Cancellations are delivered to Activities from the Temporal Service when they Heartbeat") + +--- + +#### 16. Timers +**Status:** all good + +**Verified:** +- `workflow.sleep(timedelta(...))` API ✓ +- Accepts `timedelta` objects (hours, minutes, days, etc.) ✓ +- Alternative: `asyncio.sleep()` also works (backed by workflow timer) ✓ +- "Temporal timers are server-side, so sub-second resolution might not be meaningful" + +--- + +#### 17. Local Activities +**Status:** all good + +**Verified:** +- `workflow.execute_local_activity()` API exists ✓ +- `start_to_close_timeout` parameter exists ✓ +- "Skip the task queue" explanation is accurate ✓ +- "Not durable and distributed" warning is accurate ✓ +- Temporal docs: "avoid roundtripping to the Temporal Service" and "reduced durability guarantees" + +--- + +#### 18. Using Pydantic Models +**Status:** all good + +**Verified:** +- Reference path `references/python/data-handling.md` exists ✓ +- File contains Pydantic integration documentation starting at line 15 ✓ + +--- + + +## Go + +**File:** `references/go/patterns.md` (relative to skill root) + +### Tracking + +| # | Section | Status | Fix Applied | Sources | +|---|---------|--------|-------------|---------| +| 1 | Signals | all good | | temporal-docs | +| 2 | Queries | all good | | temporal-docs | +| 3 | Updates | all good | | temporal-docs | +| 4 | Child Workflows | all good | | temporal-docs | +| 5 | Child Workflow Options | all good | | temporal-docs | +| 6 | Handles to External Workflows | all good | | temporal-docs | +| 7 | Parallel Execution | all good | | temporal-docs | +| 8 | Selector Pattern | all good | | temporal-docs | +| 9 | Continue-as-New | all good | | temporal-docs | +| 10 | Saga Pattern (Compensations) | all good | | temporal-docs | +| 11 | Cancellation Handling | all good | | temporal-docs | +| 12 | Wait Condition with Timeout | all good | | temporal-docs | +| 13 | Waiting for All Handlers to Finish | all good | | temporal-docs | +| 14 | Activity Heartbeat Details | all good | | temporal-docs | +| 15 | Timers | all good | | temporal-docs | +| 16 | Local Activities | all good | | temporal-docs | + +### Detailed Notes + +#### 1. Signals +**Status:** all good +**Verified:** +- Channel-based signal reception via `workflow.GetSignalChannel` ✓ +- `channel.Receive(ctx, &value)` pattern ✓ + +--- + +#### 2. Queries +**Status:** all good +**Verified:** +- `workflow.SetQueryHandler` API ✓ +- Synchronous handler returning value and error ✓ + +--- + +#### 3. Updates +**Status:** all good +**Verified:** +- `workflow.SetUpdateHandler` with optional validator ✓ +- Handler and validator signatures ✓ + +--- + +#### 4. Child Workflows +**Status:** all good +**Verified:** +- `workflow.ExecuteChildWorkflow` API ✓ +- Returns Future, `.Get(ctx, &result)` pattern ✓ + +--- + +#### 5. Child Workflow Options +**Status:** all good +**Verified:** +- `workflow.ChildWorkflowOptions` struct fields ✓ +- `ParentClosePolicy` values ✓ + +--- + +#### 6. Handles to External Workflows +**Status:** all good +**Verified:** +- `workflow.SignalExternalWorkflow` API ✓ + +--- + +#### 7. Parallel Execution +**Status:** all good +**Verified:** +- `workflow.Go` for spawning coroutines ✓ +- Selector pattern for parallel coordination ✓ + +--- + +#### 8. Selector Pattern +**Status:** all good +**Verified:** +- `workflow.NewSelector` API ✓ +- `AddFuture`, `AddReceive` methods ✓ +- `Select(ctx)` to block until one callback fires ✓ + +--- + +#### 9. Continue-as-New +**Status:** all good +**Verified:** +- `workflow.NewContinueAsNewError` API ✓ +- Return the error to trigger continue-as-new ✓ + +--- + +#### 10. Saga Pattern (Compensations) +**Status:** all good +**Verified:** +- Compensation slice pattern with LIFO execution ✓ +- Save compensation BEFORE calling activity ✓ + +--- + +#### 11. Cancellation Handling +**Status:** all good +**Verified:** +- `workflow.NewDisconnectedContext` for cleanup after cancellation ✓ +- `ctx.Err()` check for cancellation detection ✓ + +--- + +#### 12. Wait Condition with Timeout +**Status:** all good +**Verified:** +- Selector with timer future for timeout ✓ +- `workflow.NewTimer` API ✓ + +--- + +#### 13. Waiting for All Handlers to Finish +**Status:** all good +**Verified:** +- `workflow.AllHandlersFinished` API ✓ +- `workflow.Await(ctx, workflow.AllHandlersFinished)` pattern ✓ + +--- + +#### 14. Activity Heartbeat Details +**Status:** all good +**Verified:** +- `activity.RecordHeartbeat` API ✓ +- `activity.GetHeartbeatDetails` for resume ✓ +- Cancellation delivery via heartbeat ✓ + +--- + +#### 15. Timers +**Status:** all good +**Verified:** +- `workflow.Sleep(ctx, duration)` API ✓ +- `workflow.NewTimer(ctx, duration)` for cancellable timers ✓ + +--- + +#### 16. Local Activities +**Status:** all good +**Verified:** +- `workflow.ExecuteLocalActivity` API ✓ +- `workflow.LocalActivityOptions` struct ✓ + +--- + diff --git a/.memory/correctness_checking/sync-vs-async.md b/.memory/correctness_checking/sync-vs-async.md new file mode 100644 index 0000000..7c6cd87 --- /dev/null +++ b/.memory/correctness_checking/sync-vs-async.md @@ -0,0 +1,191 @@ +# sync-vs-async.md + +Correctness verification for `references/python/sync-vs-async.md` (Python only). + +## Python + +**File:** `references/python/sync-vs-async.md` (relative to skill root) + +### Tracking + +| # | Section | Status | Fix Applied | Sources | +|---|---------|--------|-------------|---------| +| 1 | Overview | all good | | context7 sdk-python | +| 2 | Recommendation: Default to Synchronous | all good | | context7 sdk-python | +| 3 | The Event Loop Problem | all good | | context7 sdk-python | +| 4 | Synchronous Activities | all good | | context7 sdk-python | +| 5 | Asynchronous Activities | all good | | context7 sdk-python, aiohttp docs | +| 6 | HTTP Libraries: A Critical Choice | all good | | context7 sdk-python, temporal-docs | +| 7 | Running Blocking Code in Async Activities | all good | | context7 sdk-python | +| 8 | When to Use Async Activities | all good | | context7 sdk-python | +| 9 | When to Use Sync Activities | all good | | context7 sdk-python | +| 10 | Debugging Tip | all good | | context7 sdk-python | +| 11 | Multi-Core Usage | all good | | context7 sdk-python, temporal-docs | +| 12 | Separate Workers for Workflows vs Activities | all good | | context7 sdk-python, temporal-docs | +| 13 | Complete Example: Sync Activity | all good | | context7 sdk-python | +| 14 | Complete Example: Async Activity | all good | | context7 sdk-python | +| 15 | Summary Table | all good | | context7 sdk-python | + +### Detailed Notes + +#### 1. Overview +**Status:** all good + +**Verified:** +- Three approaches: asyncio, ThreadPoolExecutor, ProcessPoolExecutor ✓ +- SDK docs: "Asynchronous activities are functions defined with `async def`" +- SDK docs: "activity_executor... must be set with a `concurrent.futures.Executor` instance" +- SDK docs: mentions ThreadPoolExecutor for threaded and ProcessPoolExecutor for multiprocess + +--- + +#### 2. Recommendation: Default to Synchronous +**Status:** all good + +**Verified:** +- "Default to synchronous" recommendation is pragmatically sound ✓ +- SDK docs: "Threaded activities are the initial recommendation" +- SDK warning: "Do not block the thread in `async def` Python functions. This can stop the processing of the rest of the Temporal." +- Note: SDK says async is "more performant" when done correctly, but sync is safer for most developers + +--- + +#### 3. The Event Loop Problem +**Status:** all good + +**Verified:** +- Single-thread event loop explanation ✓ +- Blocking call consequences list ✓ +- SDK warning: "Do not block the thread in `async def` Python functions. This can stop the processing of the rest of the Temporal." +- "Stop the processing" confirms blocking affects entire worker + +--- + +#### 4. Synchronous Activities +**Status:** all good + +**Verified:** +- "Run in activity_executor" ✓ +- "Must provide executor" - SDK: "activity_executor... must be set" ✓ +- `ThreadPoolExecutor` context manager pattern ✓ +- `activity_executor` parameter in `Worker()` ✓ + +--- + +#### 5. Asynchronous Activities +**Status:** all good + +**Verified:** +- "Share default asyncio event loop" ✓ - no separate executor needed for async +- "Any blocking call freezes the entire loop" ✓ - confirmed by SDK warning +- `aiohttp.ClientSession` async context manager pattern ✓ - matches official aiohttp docs + +--- + +#### 6. HTTP Libraries: A Critical Choice +**Status:** all good + +**Verified:** +- `requests` blocking - SDK: "making an HTTP call with the popular `requests` library...would lead to blocking your event loop" ✓ +- `urllib3` blocking - implied (synchronous by design) ✓ +- `aiohttp` async - SDK: "This Activity uses the `aiohttp` library to make an async safe HTTP request" ✓ +- `httpx` both - SDK: "you should use an async-safe HTTP library such as `aiohttp` or `httpx`" ✓ +- BAD/GOOD examples correctly demonstrate anti-pattern and correct pattern ✓ + +--- + +#### 7. Running Blocking Code in Async Activities +**Status:** all good + +**Verified:** +- `loop.run_in_executor(None, fn)` pattern ✓ +- `asyncio.to_thread(fn)` pattern (Python 3.9+) ✓ +- SDK docs mention both: "loop.run_in_executor()" and "asyncio.to_thread()" +- Note: Modern code should prefer `asyncio.get_running_loop()` over `get_event_loop()` + +--- + +#### 8. When to Use Async Activities +**Status:** all good + +**Verified:** +- All 4 criteria are accurate guidance ✓ +- SDK: "Do not block the thread in `async def` Python functions" supports criteria 1 +- SDK: "Asynchronous activities are often much more performant" supports criteria 3 +- Criteria 2 and 4 are sound practical advice + +--- + +#### 9. When to Use Sync Activities +**Status:** all good + +**Verified:** +- All 5 use cases are accurate ✓ +- SDK: "By default, Activities should be synchronous rather than asynchronous" +- SDK: "making an HTTP call with the popular `requests` library...would lead to blocking" supports case 1 +- SDK: file I/O is listed as blocking call, supports case 2 + +--- + +#### 10. Debugging Tip +**Status:** all good + +**Verified:** +- Convert async to sync debugging approach is valid ✓ +- SDK warning: "Do not block the thread in `async def` Python functions. This can stop the processing of the rest of the Temporal." +- If bugs disappear when converting to sync, indicates blocking calls were the issue + +--- + +#### 11. Multi-Core Usage +**Status:** all good + +**Verified:** +- Multiple worker processes recommendation ✓ - SDK: "Run more than one Worker Process" +- ProcessPoolExecutor with caveats ✓ - SDK: "Users should prefer threaded activities over multiprocess ones since, among other reasons, threaded activities can raise on cancellation" +- Extra complexity: requires SharedStateManager, pickling, spawn/fork issues + +--- + +#### 12. Separate Workers for Workflows vs Activities +**Status:** all good + +**Verified:** +- Workflow-only vs Activity-only workers pattern ✓ - confirmed in Slack and community docs +- Resource contention and scaling benefits ✓ +- Note: Workflows are more memory-bound than CPU-bound; characterization could be refined but core message is correct + +--- + +#### 13. Complete Example: Sync Activity +**Status:** all good + +**Verified:** +- `@activity.defn` on sync function ✓ +- `requests` library usage appropriate for sync ✓ +- `ThreadPoolExecutor` with `max_workers=100` matches SDK examples ✓ +- Worker configuration code matches official pattern ✓ + +--- + +#### 14. Complete Example: Async Activity +**Status:** all good + +**Verified:** +- Activity class with session injection ✓ - SDK: "Activities can be defined on methods... allows the instance to carry state" +- `@activity.defn` on async method ✓ +- `async with session.get()` pattern ✓ +- No `activity_executor` needed ✓ - SDK: "When using asynchronous activities no special worker parameters are needed" + +--- + +#### 15. Summary Table +**Status:** all good + +**Verified:** +- All table cells are accurate ✓ +- "Debugging: Easier/Harder" not explicitly documented but reasonable industry knowledge +- All other cells match SDK documentation + +--- + diff --git a/.memory/correctness_checking/testing.md b/.memory/correctness_checking/testing.md new file mode 100644 index 0000000..5ccb05f --- /dev/null +++ b/.memory/correctness_checking/testing.md @@ -0,0 +1,288 @@ +# testing.md + +Correctness verification for `references/{language}/testing.md`. + +## TypeScript + +**File:** `references/typescript/testing.md` (relative to skill root) + +### Tracking + +| # | Section | Status | Fix Applied | Sources | +|---|---------|--------|-------------|---------| +| 1 | Overview | FIXED | Manually updated to encourage startLocal over time skipping | temporal-docs | +| 2 | Test Environment Setup | FIXED | Manually updated to prefer startLocal | temporal-docs | +| 3 | Activity Mocking | all good | | context7 sdk-typescript | +| 4 | Testing Signals and Queries | FIXED | Use defined signal/query objects | context7 sdk-typescript | +| 5 | Testing Failure Cases | FIXED | Added WorkflowFailedError import | context7 sdk-typescript | +| 6 | Replay Testing | FIXED | Added complete history fetching patterns | context7 sdk-typescript | +| 7 | Activity Testing | FIXED | Replaced {cancelled:true} with env.cancel() | context7 sdk-typescript | +| 8 | Best Practices | FIXED | Manually updated to prefer startLocal | temporal-docs | + +### Detailed Notes + +#### 1. Overview +**Status:** FIXED + +**Fixed:** Manually updated by user to encourage `startLocal` over time skipping. + +--- + +#### 2. Test Environment Setup +**Status:** FIXED + +**Fixed:** Manually updated by user to prefer `startLocal`. + +--- + +#### 3. Activity Mocking +**Status:** all good + +**Verified:** +- Inline activity object in `Worker.create()` for mocking is correct +- Mock function signature pattern is valid + +--- + +#### 4. Testing Signals and Queries +**Status:** FIXED + +**Fixed:** Updated to use defined signal/query objects (`defineQuery`/`defineSignal`) instead of string names. + +--- + +#### 5. Testing Failure Cases +**Status:** FIXED + +**Fixed:** Added missing `import { WorkflowFailedError } from '@temporalio/client';` + +--- + +#### 6. Replay Testing +**Status:** FIXED + +**Fixed:** Added complete history fetching patterns (from JSON file and from server). + +--- + +#### 7. Activity Testing +**Status:** FIXED + +**Fixed:** Replaced `{ cancelled: true }` with `env.cancel()` method, added `CancelledFailure` import. + +--- + +#### 8. Best Practices +**Status:** FIXED + +**Fixed:** Manually updated by user to prefer `startLocal`. + +--- + + +## Python + +**File:** `references/python/testing.md` (relative to skill root) + +### Tracking + +| # | Section | Status | Fix Applied | Sources | +|---|---------|--------|-------------|---------| +| 1 | Overview | all good | | context7 sdk-python | +| 2 | Workflow Test Environment | needs fixes | | context7 sdk-python | +| 3 | Mocking Activities | all good | | context7 sdk-python | +| 4 | Testing Signals and Queries | all good | | context7 sdk-python | +| 5 | Testing Failure Cases | all good | | context7 sdk-python | +| 6 | Workflow Replay Testing | all good | | context7 sdk-python | +| 7 | Activity Testing | all good | | context7 sdk-python | +| 8 | Best Practices | all good | | context7 sdk-python | + +### Detailed Notes + +#### 1. Overview +**Status:** all good + +**Verified:** +- `WorkflowEnvironment` from `temporalio.testing` ✓ +- `ActivityEnvironment` from `temporalio.testing` ✓ + +--- + +#### 2. Workflow Test Environment +**Status:** needs fixes + +**Verified:** +- `WorkflowEnvironment.start_local()` API ✓ +- `async with await WorkflowEnvironment.start_local() as env` pattern ✓ +- `env.client` property ✓ +- `async with Worker(...)` context manager ✓ +- `env.client.execute_workflow()` API ✓ +- `@pytest.mark.asyncio` decorator ✓ +- `WorkflowEnvironment.start_time_skipping()` API ✓ +- "Cannot be shared among tests" for time-skipping ✓ + +**Issues:** +- **Code example has bug:** `task_queue` variable is used in `execute_workflow()` but never defined +- Should define `task_queue = str(uuid.uuid4())` before the Worker context + +--- + +#### 3. Mocking Activities +**Status:** all good + +**Verified:** +- `@activity.defn(name="...")` for mock with same name ✓ +- Register mock activity with Worker instead of real one ✓ +- SDK: "Simply write different ones and pass those to the worker" + +--- + +#### 4. Testing Signals and Queries +**Status:** all good + +**Verified:** +- `env.client.start_workflow()` returns handle ✓ +- `handle.signal(Workflow.signal_method, data)` API ✓ +- `handle.query(Workflow.query_method)` API ✓ +- `handle.result()` API ✓ + +--- + +#### 5. Testing Failure Cases +**Status:** all good + +**Verified:** +- `ApplicationError(..., non_retryable=True)` from `temporalio.exceptions` ✓ +- `WorkflowFailureError` from `temporalio.client` ✓ +- `pytest.raises(WorkflowFailureError)` pattern ✓ + +--- + +#### 6. Workflow Replay Testing +**Status:** all good + +**Verified:** +- `Replayer` import from `temporalio.worker` ✓ +- `WorkflowHistory` import from `temporalio.client` ✓ +- `Replayer(workflows=[...])` constructor ✓ +- `replayer.replay_workflow()` API ✓ +- `WorkflowHistory.from_json()` API ✓ +- Note: SDK examples use positional args but keyword args in section should also work + +--- + +#### 7. Activity Testing +**Status:** all good + +**Verified:** +- `ActivityEnvironment` from `temporalio.testing` ✓ +- `ActivityEnvironment()` constructor ✓ +- `env.run(activity_fn, *args)` API ✓ +- Note: Section is minimal but accurate; ActivityEnvironment has additional features (info, on_heartbeat, cancel) + +--- + +#### 8. Best Practices +**Status:** all good + +**Verified:** +- All 6 best practices are valid ✓ +- UUID recommendation for test isolation ✓ +- Time-skipping for workflows with timers ✓ +- Replay tests for determinism verification ✓ +- `async with Worker(...)` context manager +- `env.client.execute_workflow()` API +- `@pytest.mark.asyncio` decorator +- UUID for task queue and workflow ID pattern +- `WorkflowEnvironment.start_time_skipping()` API +- "Cannot be shared among tests" for time-skipping claim + +--- + + +## Go + +**File:** `references/go/testing.md` (relative to skill root) + +### Tracking + +| # | Section | Status | Fix Applied | Sources | +|---|---------|--------|-------------|---------| +| 1 | Overview | all good | | temporal-docs | +| 2 | Test Environment Setup | all good | | temporal-docs | +| 3 | Activity Mocking | all good | | temporal-docs | +| 4 | Testing Signals and Queries | all good | | temporal-docs | +| 5 | Testing Failure Cases | all good | | temporal-docs | +| 6 | Replay Testing | all good | | temporal-docs | +| 7 | Activity Testing | all good | | temporal-docs | +| 8 | Best Practices | all good | | temporal-docs | + +### Detailed Notes + +#### 1. Overview +**Status:** all good +**Verified:** +- `testsuite` package for workflow/activity testing ✓ +- testify library for assertions and mocking ✓ +- Automatic time-skipping support ✓ + +--- + +#### 2. Test Environment Setup +**Status:** all good +**Verified:** +- `testsuite.WorkflowTestSuite` struct ✓ +- `TestWorkflowEnvironment` via `suite.NewTestWorkflowEnvironment()` ✓ +- Struct-based and function-based approaches ✓ + +--- + +#### 3. Activity Mocking +**Status:** all good +**Verified:** +- `env.OnActivity` for mocking ✓ +- `Return(value, nil)` pattern ✓ + +--- + +#### 4. Testing Signals and Queries +**Status:** all good +**Verified:** +- `env.RegisterDelayedCallback` for timed signals ✓ +- `env.SignalWorkflow` API ✓ +- `env.QueryWorkflow` API ✓ + +--- + +#### 5. Testing Failure Cases +**Status:** all good +**Verified:** +- `env.ExecuteWorkflow` API ✓ +- `env.IsWorkflowCompleted()` check ✓ +- `env.GetWorkflowError()` for error assertions ✓ + +--- + +#### 6. Replay Testing +**Status:** all good +**Verified:** +- `worker.NewWorkflowReplayer` API ✓ +- `ReplayWorkflowHistoryFromJSONFile` API ✓ + +--- + +#### 7. Activity Testing +**Status:** all good +**Verified:** +- `TestActivityEnvironment` from `testsuite` ✓ +- `env.ExecuteActivity` API ✓ + +--- + +#### 8. Best Practices +**Status:** all good +**Verified:** +- All best practices valid ✓ + +--- + diff --git a/.memory/correctness_checking/versioning.md b/.memory/correctness_checking/versioning.md new file mode 100644 index 0000000..4885ddd --- /dev/null +++ b/.memory/correctness_checking/versioning.md @@ -0,0 +1,343 @@ +# versioning.md + +Correctness verification for `references/{language}/versioning.md`. + +## TypeScript + +**File:** `references/typescript/versioning.md` (relative to skill root) + +### Tracking + +| # | Section | Status | Fix Applied | Sources | +|---|---------|--------|-------------|---------| +| 1 | Overview | all good | | context7 sdk-typescript | +| 2 | Why Versioning Matters | FIXED | Improved non-determinism explanation | context7 sdk-typescript | +| 3 | Workflow Versioning with the Patching API | all good | | context7 sdk-typescript | +| 4 | Three-Step Patching Process | all good | | context7 sdk-typescript | +| 5 | Multiple Patches | FIXED | Clarified same patchId for related changes | context7 sdk-typescript | +| 6 | Query Filters for Versioned Workflows | FIXED | Added spaces around = operator | context7 sdk-typescript | +| 7 | Workflow Type Versioning | all good | | context7 sdk-typescript | +| 8 | Worker Versioning | FIXED | Updated to 2025 Public Preview API | context7 sdk-typescript, temporal-docs | +| 9 | Choosing a Versioning Strategy | FIXED | Corrected deprecation info - only legacy API deprecated | context7 sdk-typescript, temporal-docs | +| 10 | Best Practices | FIXED | Removed incorrect deprecation notes | context7 sdk-typescript, temporal-docs | + +### Detailed Notes + +#### 1. Overview +**Status:** all good + +**Verified:** Three approaches (Patching API, Workflow Type Versioning, Worker Versioning) are correctly listed + +--- + +#### 2. Why Versioning Matters +**Status:** FIXED + +**Fixed:** Improved non-determinism explanation to clarify it's about different execution paths and command sequences. + +--- + +#### 3. Workflow Versioning with the Patching API +**Status:** all good + +**Verified:** patched() import, boolean return, marker insertion, replay behavior all correct + +**SDK Team Feedback (for Go):** TypeScript `patched()` is NOT memoized on negative return (can use in loops, may need manual memoization for coordinated changes). Python/.NET/Ruby ARE memoized (cannot use in loops, workaround: append sequence number to patch ID). See temporalio/features#591. + +--- + +#### 4. Three-Step Patching Process +**Status:** all good + +**Verified:** All three steps are correct - patched() with both paths, deprecatePatch() API, clean removal + +--- + +#### 5. Multiple Patches +**Status:** FIXED + +**Fixed:** Clarified that it's about using same patchId in multiple patched() calls for related changes. + +--- + +#### 6. Query Filters for Versioned Workflows +**Status:** FIXED + +**Fixed:** Added spaces around `=` operator in query examples. IS NULL syntax verified as correct. + +--- + +#### 7. Workflow Type Versioning +**Status:** all good + +**Verified:** V2 pattern, worker registration, client code, List Filter all correct + +--- + +#### 8. Worker Versioning +**Status:** FIXED + +**Fixed:** Completely rewrote section with correct 2025 Public Preview API. Key changes: +- Added note that Worker Versioning is in **Public Preview** (not deprecated) +- Clarified that only the **legacy** Worker Versioning API (pre-2025) is being removed in March 2026 +- Updated to use `workerDeploymentOptions` configuration with `useWorkerVersioning`, `version.deploymentName`, `version.buildId` +- Removed detailed PINNED/AUTO_UPGRADE behaviors and deployment strategies (simplified for skill token efficiency) +- Added deployment workflow using Temporal CLI + +--- + +#### 9. Choosing a Versioning Strategy +**Status:** FIXED + +**Fixed:** Removed incorrect deprecation notice. Worker Versioning is actively supported (Public Preview). Updated table to show Worker Versioning as a valid option for short-running workflows and frequent deploys. + +--- + +#### 10. Best Practices +**Status:** FIXED + +**Fixed:** Removed incorrect deprecation notes from best practices. Added Worker Versioning-specific practices (consistent deployment names, traceable Build IDs). + +--- + + +## Python + +**File:** `references/python/versioning.md` (relative to skill root) + +### Tracking + +| # | Section | Status | Fix Applied | Sources | +|---|---------|--------|-------------|---------| +| 1 | Overview | needs fixes | | context7 sdk-python, temporal-docs | +| 2 | Why Versioning is Needed | all good | | context7 sdk-python, temporal-docs | +| 3 | The patched() Function | all good | | context7 sdk-python, temporal-docs | +| 4 | Three-Step Patching Process | all good | | context7 sdk-python, temporal-docs | +| 5 | Branching with Multiple Patches | all good | | context7 sdk-python, temporal-docs | +| 6 | Query Filters for Finding Workflows by Version | all good | | context7 sdk-python, temporal-docs | +| 7 | Workflow Type Versioning | all good | | context7 sdk-python, temporal-docs | +| 8 | Worker Versioning Key Concepts | all good | | context7 sdk-python, temporal-docs | +| 9 | Configuring Workers for Versioning | needs fixes | | context7 sdk-python, temporal-docs | +| 10 | PINNED vs AUTO_UPGRADE Behaviors | needs fixes | | context7 sdk-python, temporal-docs | +| 11 | Worker Configuration with Default Behavior | all good | | context7 sdk-python, temporal-docs | +| 12 | Deployment Strategies | all good | | context7 sdk-python, temporal-docs | +| 13 | Querying Workflows by Worker Version | all good | | context7 sdk-python, temporal-docs | +| 14 | Choosing a Strategy | needs fixes | | context7 sdk-python, temporal-docs | +| 15 | Best Practices | all good | | context7 sdk-python, temporal-docs | + +### Detailed Notes + +#### 1. Overview +**Status:** needs fixes + +**Issues:** +- **Lists 3 approaches but official docs list 2 primary methods:** + - Official: Patching API, Worker Versioning (2 primary) + - Section: Patching API, Workflow Type Versioning, Worker Versioning (3) +- Workflow Type Versioning is acknowledged in learning materials but NOT listed as primary in SDK docs +- SDK docs: "There are two primary Versioning methods" +- Workflow Type Versioning is more of a manual convention than SDK-provided mechanism + +--- + +#### 2. Why Versioning is Needed +**Status:** all good + +**Verified:** +- History Replay explanation ✓ - "Workers will resume those executions automatically after the restart. They do this through History Replay" +- Non-deterministic error cause ✓ - "If that produces a different sequence of Commands than the code in use before the restart, then it will result in a non-deterministic error" +- Three-point explanation is accurate ✓ + +--- + +#### 3. The patched() Function +**Status:** all good + +**Verified:** +- `workflow.patched("patch-id")` API returns bool ✓ +- "For new executions returns True and records marker" behavior ✓ +- "For replay with marker returns True" behavior ✓ +- "For replay without marker returns False" behavior ✓ + +**SDK Team Feedback (for Go):** Python `patched()` IS memoized on first call (cannot use in loops, workaround: append sequence number to patch ID). TypeScript is NOT memoized on negative return (can use in loops). Check Go SDK behavior. See temporalio/features#591. + +--- + +#### 4. Three-Step Patching Process +**Status:** all good + +**Verified:** +- Step 1: `workflow.patched()` with both code paths ✓ +- Step 2: `workflow.deprecate_patch()` API ✓ +- Step 3: Remove deprecate_patch call ✓ +- Process aligns with official SDK documentation + +--- + +#### 5. Branching with Multiple Patches +**Status:** all good + +**Verified:** +- Multiple `workflow.patched()` calls in if/elif/else chain ✓ +- Single patch ID for multiple changes pattern ✓ +- Code example correctly demonstrates branching logic + +--- + +#### 6. Query Filters for Finding Workflows by Version +**Status:** all good + +**Verified:** +- `TemporalChangeVersion` search attribute ✓ +- `TemporalChangeVersion IS NULL` for pre-patch workflows ✓ +- CLI query syntax is correct ✓ + +--- + +#### 7. Workflow Type Versioning +**Status:** all good + +**Verified:** +- `@workflow.defn(name="...")` for explicit name ✓ +- New workflow class with V2 suffix pattern ✓ +- Register both workflows with Worker ✓ +- Check for open executions CLI command ✓ + +--- + +#### 8. Worker Versioning Key Concepts +**Status:** all good + +**Verified:** +- Worker Deployment definition accurate ✓ +- Worker Deployment Version definition (deployment name + Build ID) ✓ +- Conceptual explanations align with official documentation + +--- + +#### 9. Configuring Workers for Versioning +**Status:** needs fixes + +**Issues:** +- **Wrong import paths for Worker Versioning classes:** + - Doc shows: `from temporalio.worker.deployment_config import WorkerDeploymentConfig, WorkerDeploymentVersion` + - Correct: `WorkerDeploymentConfig` from `temporalio.worker` + - Correct: `WorkerDeploymentVersion` from `temporalio.common` +- `deployment_config` parameter in `Worker()` is correct ✓ +- Constructor patterns are correct ✓ + +--- + +#### 10. PINNED vs AUTO_UPGRADE Behaviors +**Status:** needs fixes + +**Issues:** +- **Wrong import location for VersioningBehavior:** + - Doc shows: `from temporalio.workflow import VersioningBehavior` + - Correct: `from temporalio.common import VersioningBehavior` +- PINNED behavior description is correct ✓ +- AUTO_UPGRADE behavior description is correct ✓ +- "AUTO_UPGRADE still needs patching" claim is accurate ✓ +- Use case recommendations are valid ✓ + +--- + +#### 11. Worker Configuration with Default Behavior +**Status:** all good + +**Verified:** +- `default_versioning_behavior` parameter correctly shown ✓ +- `os.environ["BUILD_ID"]` pattern is reasonable ✓ +- Configuration example is accurate + +--- + +#### 12. Deployment Strategies +**Status:** all good + +**Verified:** +- Blue-Green deployment description accurate ✓ +- Rainbow deployment description accurate ✓ +- Kubernetes ReplicaSets mention is appropriate ✓ + +--- + +#### 13. Querying Workflows by Worker Version +**Status:** all good + +**Verified:** +- `TemporalWorkerDeploymentVersion` search attribute ✓ +- CLI query syntax is correct ✓ + +--- + +#### 14. Choosing a Strategy +**Status:** needs fixes + +**Issues:** +- **Missing deprecation notice:** The pre-2025 Worker Versioning API (Build ID-based versioning) is being removed in March 2026 +- Decision table and factors are otherwise accurate +- Should add note about deprecation timeline for old Worker Versioning + +--- + +#### 15. Best Practices +**Status:** all good + +**Verified:** +- All 7 best practices are valid ✓ +- Guidance aligns with official documentation + +--- + + +## Go + +**File:** `references/go/versioning.md` (relative to skill root) + +### Tracking + +| # | Section | Status | Fix Applied | Sources | +|---|---------|--------|-------------|---------| +| 1 | GetVersion API | all good | | temporal-docs | +| 2 | Workflow Type Versioning | all good | | temporal-docs | +| 3 | Worker Versioning | all good | | temporal-docs | +| 4 | Best Practices | all good | | temporal-docs | + +### Detailed Notes + +#### 1. GetVersion API +**Status:** all good +**Verified:** +- `workflow.GetVersion(ctx, "changeID", workflow.DefaultVersion, maxSupported)` API ✓ +- `workflow.DefaultVersion` constant ✓ +- Three-step lifecycle (version with both paths, deprecate, remove) ✓ + +--- + +#### 2. Workflow Type Versioning +**Status:** all good +**Verified:** +- V2 workflow function pattern ✓ +- Worker registration of both versions ✓ + +--- + +#### 3. Worker Versioning +**Status:** all good +**Verified:** +- `worker.DeploymentOptions` struct ✓ +- `worker.WorkerDeploymentVersion` with `DeploymentName` and `BuildId` fields ✓ +- `UseVersioning` field ✓ +- `DefaultVersioningBehavior` field ✓ +- `workflow.VersioningBehaviorPinned` / `workflow.VersioningBehaviorAutoUpgrade` constants ✓ + +--- + +#### 4. Best Practices +**Status:** all good +**Verified:** +- All best practices valid ✓ + +--- + diff --git a/.memory/sdk-versions.json b/.memory/sdk-versions.json new file mode 100644 index 0000000..2c7e383 --- /dev/null +++ b/.memory/sdk-versions.json @@ -0,0 +1,17 @@ +{ + "description": "Tracks the SDK version numbers against which the skill's reference files were last verified.", + "sdks": { + "python": { + "repo": "temporalio/sdk-python", + "version": "1.22.0" + }, + "typescript": { + "repo": "temporalio/sdk-typescript", + "version": "1.14.1" + }, + "go": { + "repo": "temporalio/sdk-go", + "version": "1.40.0" + } + } +} diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..efa8328 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,36 @@ +# Agent Skills Repository + +This repository contains plugin skills (in `plugins/`) and agent memory documents (in `.memory/`) for coordinating work on reference files. + +## Editing Skills and Reference Files + +When working on files inside `plugins/` or `.memory/`, use the **edit-plugin-skills** skill — it contains the full workflow for editing reference files, updating memory documents, and avoiding staleness. + +## Repository Structure + +This is a two-repo setup: +- **Outer repo** (`temporalio/agent-skills`): Plugin wrapper, `.memory/` tracking documents, `sdk-versions.json`, coordination files. +- **Submodule** (`temporalio/skill-temporal-developer`) at `plugins/temporal-developer/skills/temporal-developer/`: The actual skill content — `SKILL.md` and `references/`. + +## Branch / Development Workflow + +Both repos use `dev` as the primary working branch. Feature branches branch from and merge into `dev`, never directly into `main`. + +1. Branch from `dev`, do feature work, merge feature branch → `dev` (in the submodule) +2. Bump outer repo's submodule pointer on outer `dev` to point to latest submodule `dev` (can push directly, PR not necessary) +3. Dogfood test on `dev` + +## Release Workflow + +There is no package publishing — merging to `main` IS the release. + +1. Bump the skill version in the submodule via PR merged to submodule `dev`. Ask the user whether major, minor, or patch (semver). Update both places (must always match): + - `plugins/temporal-developer/skills/temporal-developer/SKILL.md` (frontmatter `version:`) + - `plugins/temporal-developer/.claude-plugin/plugin.json` (`"version"`) +2. Merge submodule `dev` → `main` +3. Bump outer repo's submodule pointer (on outer `dev`) to point to latest submodule `main` +4. Merge outer `dev` → `main` + +## sdk-versions.json + +Tracks SDK versions against which reference files were last verified. Updated during specific SDK-update PRs, not as part of general content work. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..d1db018 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,32 @@ +# Contributing + +Thanks for your interest in contributing to the Temporal Developer skill! + +## Where to make changes + +All skill content lives in the submodule at `plugins/temporal-developer/skills/temporal-developer/`. This is a separate repo ([temporalio/skill-temporal-developer](https://github.com/temporalio/skill-temporal-developer)) included here as a Git submodule. + +**Work within the submodule.** The outer repo (`agent-skills`) contains coordination and tracking files managed by maintainers. Contributors should focus on the submodule, where the skill definition (`SKILL.md`) and reference files (`references/`) live. + +## Branching + +The default branch for development is `dev`, not `main`. Please branch from `dev` and open PRs against `dev`. + +PRs to `main` will not be accepted — `main` is updated only during releases by merging `dev`. + +## Making a PR + +1. Fork or clone the submodule repo +2. Create a feature branch from `dev` +3. Make your changes +4. Open a PR targeting `dev` + +## What to contribute + +- Fix incorrect code examples or outdated API usage +- Improve clarity of explanations +- Add coverage for missing SDK features + +## Questions? + +Open an issue on the [skill-temporal-developer](https://github.com/temporalio/skill-temporal-developer) repo. diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..7092ef5 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 Temporal Technologies Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md index be21bf3..1b184e6 100644 --- a/README.md +++ b/README.md @@ -1 +1,29 @@ -# agent-skills +# Temporal Coding Agent Plugin Marketplace + +This repository provides a [Marketplace](https://code.claude.com/docs/en/discover-plugins) of coding agent plugins for working with [Temporal](https://temporal.io/). + +> [!WARNING] +> These plugins are in Public Preview, and will continue to evolve and improve. +> We would love to hear your feedback - positive or negative - over in the [Community Slack](https://t.mp/slack), in the [#topic-ai channel](https://temporalio.slack.com/archives/C0818FQPYKY) + +## Installation - Claude Code + +**Step 1:** Marketplace Installation + +1. Run `/plugin marketplace add temporalio/agent-skills` +2. Run `/plugin` to open the plugin manager +3. Select **Marketplaces** +4. Choose `temporal-marketplace` from the list +5. Select **Enable auto-update** or **Disable auto-update** + +**Step 2:** Plugin Installation +1. run `/plugin install temporal-developer@temporalio-agent-skills` +2. Restart Claude Code + +## Other Coding Agents + +If using other coding agents, please see **[temporal-developer](https://github.com/temporalio/skill-temporal-developer)** for installing the skill directly. + +## Current Plugins + +Presently **[temporal-developer](https://github.com/temporalio/skill-temporal-developer)** is the only plugin within this Marketplace. It aims to provide comprehensive assistance to developers writing Temporal code. diff --git a/plugins/temporal-developer/.claude-plugin/plugin.json b/plugins/temporal-developer/.claude-plugin/plugin.json new file mode 100644 index 0000000..0f95130 --- /dev/null +++ b/plugins/temporal-developer/.claude-plugin/plugin.json @@ -0,0 +1,8 @@ +{ + "name": "temporal-developer", + "description": "Comprehensive skill for developing Temporal applications.", + "version": "0.1.0", + "author": { + "name": "Temporal" + } +} \ No newline at end of file diff --git a/plugins/temporal-developer/skills/temporal-developer b/plugins/temporal-developer/skills/temporal-developer new file mode 160000 index 0000000..b5719bc --- /dev/null +++ b/plugins/temporal-developer/skills/temporal-developer @@ -0,0 +1 @@ +Subproject commit b5719bc1434d4d5a9bc6b3f2822da9d9142aff22 diff --git a/test/README.md b/test/README.md new file mode 100644 index 0000000..1451219 --- /dev/null +++ b/test/README.md @@ -0,0 +1,129 @@ +# Temporal Skill Integration Tests + +These tests validate that the Temporal skill (`plugins/temporal-developer/skills/temporal-developer`) works correctly when used with Claude Code to generate applications. + +## Test Structure + +``` +test/ +├── python/ +│ ├── run-integration-test.sh # Full integration test +│ └── test-prompt.txt # Prompt for code generation +└── typescript/ + ├── run-integration-test.sh # Full integration test + └── test-prompt.txt # Prompt for code generation +``` + +## What These Tests Do + +1. **Set up a test workspace** with the skill installed in `.claude/skills/` +2. **Invoke Claude CLI** with a test prompt that triggers skill usage +3. **Validate generated code**: + - Correct file structure + - Required patterns present (decorators, async/await) + - Valid syntax + - Proper dependencies +4. **Optionally run the application** with a real Temporal server + +## Prerequisites + +### Required +- **Claude CLI**: `curl -fsSL https://claude.ai/install.sh | bash` +- **Anthropic API Key**: Set `ANTHROPIC_API_KEY` environment variable +- **Python 3.10+** (for Python tests) +- **Node.js 18+** (for TypeScript tests) + +### Optional (for execution tests) +- **Temporal CLI**: `brew install temporal` (macOS) or see [docs.temporal.io/cli](https://docs.temporal.io/cli) + +## Running Tests + +### Python + +```bash +# Full test (with execution) +export ANTHROPIC_API_KEY='your-key' +cd test/python +./run-integration-test.sh + +# Validation only (skip execution) +SKIP_EXECUTION=true ./run-integration-test.sh +``` + +### TypeScript + +```bash +# Full test (with execution) +export ANTHROPIC_API_KEY='your-key' +cd test/typescript +./run-integration-test.sh + +# Validation only (skip execution) +SKIP_EXECUTION=true ./run-integration-test.sh +``` + +## Manual Testing + +If you don't have the Claude CLI: + +1. Set up the test workspace: + ```bash + cd test/python # or test/typescript + ./run-integration-test.sh # Will fail at CLI check but set up workspace + ``` + +2. Navigate to the workspace: + ```bash + cd test-workspace + ``` + +3. Use Claude (any interface) to generate code from `test-prompt.txt` + +4. Validate the generated code: + ```bash + ./validate.sh + ``` + +## Test Results + +### Success +``` +╔════════════════════════════════════════════════╗ +║ FULL INTEGRATION TEST PASSED! ║ +╚════════════════════════════════════════════════╝ +``` + +### Partial Success (validation passed, execution failed) +``` +╔════════════════════════════════════════════════╗ +║ PARTIAL SUCCESS ║ +║ Structure & Validation: PASSED ║ +║ Execution Test: FAILED ║ +╚════════════════════════════════════════════════╝ +``` + +This indicates the generated code is structurally correct but had runtime issues. + +## Troubleshooting + +### "Claude CLI not found" +```bash +npm install -g @anthropic-ai/claude-code +``` + +### "ANTHROPIC_API_KEY not set" +```bash +export ANTHROPIC_API_KEY='your-key-here' +``` + +### "Temporal CLI not found" +Either install Temporal CLI or skip execution tests: +```bash +SKIP_EXECUTION=true ./run-integration-test.sh +``` + +### Python syntax errors +Check that generated code uses proper async/await and decorators. + +### TypeScript compilation errors +The test will note these but continue - some errors may be due to missing type definitions that would resolve with full dependency installation. diff --git a/test/lib/common.sh b/test/lib/common.sh new file mode 100755 index 0000000..11c4c57 --- /dev/null +++ b/test/lib/common.sh @@ -0,0 +1,249 @@ +#!/bin/bash +# Common functions and variables for integration tests + +# Colors +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' + +# Print functions +print_header() { + local title="$1" + local padded=$(printf "%-44s" "$title") + echo -e "${BLUE}╔════════════════════════════════════════════════╗${NC}" + echo -e "${BLUE}║ ${padded}║${NC}" + echo -e "${BLUE}╚════════════════════════════════════════════════╝${NC}" + echo "" +} + +print_step() { + echo -e "${YELLOW}[$(date +%H:%M:%S)] $1${NC}" +} + +print_success() { + echo -e "${GREEN}✓ $1${NC}" +} + +print_error() { + echo -e "${RED}✗ $1${NC}" +} + +print_result_box() { + local color="$1" + local line1="$2" + local line2="${3:-}" + local line3="${4:-}" + + echo -e "\n${color}╔════════════════════════════════════════════════╗${NC}" + echo -e "${color}║ ${line1}${NC}" + if [ -n "$line2" ]; then + echo -e "${color}║ ${line2}${NC}" + fi + if [ -n "$line3" ]; then + echo -e "${color}║ ${line3}${NC}" + fi + echo -e "${color}╚════════════════════════════════════════════════╝${NC}\n" +} + +# Setup paths - call this from the language-specific script +setup_paths() { + SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[1]}")" && pwd)" + TEST_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" + REPO_ROOT="$(cd "$TEST_ROOT/.." && pwd)" + SKILL_DIR="${REPO_ROOT}/plugins/temporal-developer/skills/temporal-developer" + WORKSPACE_DIR="${SCRIPT_DIR}/test-workspace" +} + +# Setup workspace with skill installed +setup_workspace() { + print_step "Setting up test workspace..." + + rm -rf "${WORKSPACE_DIR}" + mkdir -p "${WORKSPACE_DIR}/.claude/skills/temporal-developer" + + cp -r "${SKILL_DIR}"/* "${WORKSPACE_DIR}/.claude/skills/temporal-developer/" + print_success "Installed skill files" + + cp "${SCRIPT_DIR}/test-prompt.txt" "${WORKSPACE_DIR}/" + print_success "Copied test prompt" + + cp "${SCRIPT_DIR}/validate.sh" "${WORKSPACE_DIR}/" + chmod +x "${WORKSPACE_DIR}/validate.sh" + print_success "Copied validation script" + + print_success "Workspace setup complete" + echo "" +} + +# Check for Claude CLI +check_claude_cli() { + print_step "Checking for Claude CLI..." + + if ! command -v claude &> /dev/null; then + print_error "Claude CLI not found" + echo "" + echo "Install with: curl -fsSL https://claude.ai/install.sh | bash" + exit 1 + fi + + print_success "Claude CLI found" + echo "" +} + +# Check for API key +check_api_key() { + print_step "Checking for API key..." + + if [ -z "$ANTHROPIC_API_KEY" ]; then + print_error "ANTHROPIC_API_KEY environment variable not set" + echo "" + echo "Set it with: export ANTHROPIC_API_KEY='your-key-here'" + exit 1 + fi + + print_success "API key found" + echo "" +} + +# Generate code using Claude CLI +generate_code() { + print_step "Generating code using Claude CLI..." + echo "" + + cd "${WORKSPACE_DIR}" + PROMPT=$(cat test-prompt.txt) + + # Use -p for non-interactive mode, --dangerously-skip-permissions to allow file writes + if claude -p --dangerously-skip-permissions "$PROMPT" 2>&1; then + print_success "Code generation complete" + else + print_error "Code generation failed" + exit 1 + fi + echo "" +} + +# Run validation +run_validation() { + print_step "Validating generated code..." + echo "" + + cd "${WORKSPACE_DIR}" + ./validate.sh + + if [ $? -ne 0 ]; then + print_error "Validation failed" + echo "" + echo "Generated files location: ${WORKSPACE_DIR}" + exit 1 + fi + + echo "" + print_success "Validation passed" + echo "" +} + +# Check if Temporal server is running (check if gRPC port 7233 is listening) +check_temporal() { + nc -z localhost 7233 2>/dev/null + return $? +} + +# Start Temporal server +start_temporal() { + echo -e "${YELLOW}Starting Temporal development server...${NC}" + + if ! command -v temporal &> /dev/null; then + echo -e "${RED}✗ Temporal CLI not found${NC}" + echo -e "Install it with:" + echo -e " ${YELLOW}brew install temporal${NC} (macOS)" + echo -e " Or follow: https://docs.temporal.io/cli" + return 1 + fi + + temporal server start-dev > temporal-server.log 2>&1 & + TEMPORAL_PID=$! + echo $TEMPORAL_PID > .temporal-server.pid + + echo -e " Started Temporal server (PID: $TEMPORAL_PID)" + echo -e " Waiting for server to be ready..." + + for i in {1..30}; do + if check_temporal; then + echo -e "${GREEN}✓ Temporal server is ready${NC}" + return 0 + fi + sleep 1 + echo -n "." + done + + echo -e "\n${RED}✗ Temporal server failed to start${NC}" + # Kill the failed server + kill $TEMPORAL_PID 2>/dev/null || true + rm -f .temporal-server.pid + return 1 +} + +# Ensure Temporal is running, returns whether we started it +ensure_temporal() { + if check_temporal; then + echo -e "${GREEN}✓ Temporal server is already running${NC}" + TEMPORAL_STARTED_BY_US=false + return 0 + else + if start_temporal; then + TEMPORAL_STARTED_BY_US=true + return 0 + else + return 1 + fi + fi +} + +# Cleanup Temporal if we started it +cleanup_temporal() { + if [ "$TEMPORAL_STARTED_BY_US" = "true" ] && [ -f ".temporal-server.pid" ]; then + kill $(cat .temporal-server.pid) 2>/dev/null || true + rm -f .temporal-server.pid + fi + rm -f temporal-server.log +} + +# Start execution test phase +start_execution_test() { + print_step "Testing execution (optional)..." + echo "" + + if [ "$SKIP_EXECUTION" = "true" ]; then + echo -e "${YELLOW}Skipping execution test (SKIP_EXECUTION=true)${NC}" + print_result_box "$GREEN" "INTEGRATION TEST PASSED! " "(Structure & Validation) " + exit 0 + fi + + echo -e "${YELLOW}Running execution test (set SKIP_EXECUTION=true to skip)${NC}\n" + + cd "${WORKSPACE_DIR}" + + if ! ensure_temporal; then + cleanup_temporal # Clean up any partially started server + echo -e "${YELLOW}Skipping execution test - Temporal not available${NC}" + print_result_box "$GREEN" "INTEGRATION TEST PASSED! " "(Structure & Validation Only) " + exit 0 + fi +} + +# Report final execution result +report_execution_result() { + local success="$1" + + cleanup_temporal + rm -f worker.log + + if [ "$success" = "true" ]; then + print_result_box "$GREEN" "FULL INTEGRATION TEST PASSED! " + else + print_result_box "$YELLOW" "PARTIAL SUCCESS " "Structure & Validation: PASSED " "Execution Test: FAILED " + fi +} diff --git a/test/python/.gitignore b/test/python/.gitignore new file mode 100644 index 0000000..592f86d --- /dev/null +++ b/test/python/.gitignore @@ -0,0 +1 @@ +test-workspace/ diff --git a/test/python/run-integration-test.sh b/test/python/run-integration-test.sh new file mode 100755 index 0000000..f9ae8af --- /dev/null +++ b/test/python/run-integration-test.sh @@ -0,0 +1,52 @@ +#!/bin/bash +set -e + +# Load common functions +source "$(dirname "${BASH_SOURCE[0]}")/../lib/common.sh" + +setup_paths +print_header "Temporal Python Skill Integration Test" + +# Common setup and validation +setup_workspace +check_claude_cli +check_api_key +generate_code +run_validation + +# Python-specific execution test +start_execution_test + +# Install dependencies +if [ -f "requirements.txt" ]; then + echo -e "${YELLOW}Installing dependencies...${NC}" + pip install -r requirements.txt > /dev/null 2>&1 || true +fi + +# Start worker +echo -e "${YELLOW}Starting worker...${NC}" +python3 worker.py > worker.log 2>&1 & +WORKER_PID=$! +sleep 5 + +if ! kill -0 $WORKER_PID 2>/dev/null; then + echo -e "${RED}✗ Worker failed to start${NC}" + tail -20 worker.log + cleanup_temporal + exit 1 +fi +echo -e "${GREEN}✓ Worker is running${NC}" + +# Run client (with 30 second timeout) +echo -e "${YELLOW}Running client...${NC}" +if timeout 30 python3 client.py TestUser 2>&1; then + echo -e "${GREEN}✓ Workflow executed successfully${NC}" + EXECUTION_SUCCESS=true +else + echo -e "${RED}✗ Workflow execution failed or timed out${NC}" + EXECUTION_SUCCESS=false +fi + +# Cleanup +kill $WORKER_PID 2>/dev/null || true +report_execution_result "$EXECUTION_SUCCESS" diff --git a/test/python/test-prompt.txt b/test/python/test-prompt.txt new file mode 100644 index 0000000..79a2f02 --- /dev/null +++ b/test/python/test-prompt.txt @@ -0,0 +1,20 @@ +Create a complete Temporal workflow application in Python that demonstrates a greeting workflow. + +Requirements: +1. Create a workflow that takes a name parameter and returns a greeting message +2. Create an activity that formats the greeting +3. Include a worker that registers the workflow and activity +4. Include a client that starts the workflow, with a given name passed via the CLI, e.g. `python client.py Jake` +5. Use proper async/await patterns +6. Include type hints on all function signatures +7. Use the latest version of the temporalio package +8. Create these files in the current directory (not in a subdirectory): + - workflows.py + - activities.py + - worker.py + - client.py + - requirements.txt +9. Add a signal handler to the workflow that can update the greeting style +10. Add a query handler to get the current greeting count + +The application should be production-ready with proper error handling and best practices. diff --git a/test/python/validate.sh b/test/python/validate.sh new file mode 100755 index 0000000..a6e0e22 --- /dev/null +++ b/test/python/validate.sh @@ -0,0 +1,131 @@ +#!/bin/bash +set -e + +GREEN='\033[0;32m' +RED='\033[0;31m' +YELLOW='\033[1;33m' +NC='\033[0m' + +echo "=========================================" +echo "Validating Generated Python Application" +echo "=========================================" +echo "" + +# Check required files +echo "Checking file structure..." +REQUIRED_FILES=("workflows.py" "activities.py" "worker.py" "client.py") +MISSING_FILES=() + +for file in "${REQUIRED_FILES[@]}"; do + if [ ! -f "$file" ]; then + MISSING_FILES+=("$file") + else + echo -e "${GREEN}✓${NC} $file exists" + fi +done + +# Check for dependency file +if [ ! -f "requirements.txt" ] && [ ! -f "pyproject.toml" ]; then + echo -e "${RED}✗${NC} Missing dependency file (requirements.txt or pyproject.toml)" + MISSING_FILES+=("requirements.txt or pyproject.toml") +else + [ -f "requirements.txt" ] && echo -e "${GREEN}✓${NC} requirements.txt exists" + [ -f "pyproject.toml" ] && echo -e "${GREEN}✓${NC} pyproject.toml exists" +fi + +if [ ${#MISSING_FILES[@]} -gt 0 ]; then + echo "" + echo -e "${RED}❌ Missing required files:${NC}" + for file in "${MISSING_FILES[@]}"; do + echo " - $file" + done + exit 1 +fi + +echo "" +echo "Checking code patterns..." + +# Check for workflow decorator +if ! grep -q "@workflow.defn" workflows.py; then + echo -e "${RED}✗${NC} Missing @workflow.defn decorator in workflows.py" + exit 1 +fi +echo -e "${GREEN}✓${NC} Contains @workflow.defn decorator" + +# Check for activity decorator +if ! grep -q "@activity.defn" activities.py; then + echo -e "${RED}✗${NC} Missing @activity.defn decorator in activities.py" + exit 1 +fi +echo -e "${GREEN}✓${NC} Contains @activity.defn decorator" + +# Check for @workflow.run +if ! grep -q "@workflow.run" workflows.py; then + echo -e "${RED}✗${NC} Missing @workflow.run decorator in workflows.py" + exit 1 +fi +echo -e "${GREEN}✓${NC} Contains @workflow.run decorator" + +# Check for async/await +if ! grep -q "async def" workflows.py || ! grep -q "await" workflows.py; then + echo -e "${RED}✗${NC} Missing async/await syntax in workflows.py" + exit 1 +fi +echo -e "${GREEN}✓${NC} Uses async/await syntax" + +# Check for temporalio imports +if ! grep -q "from temporalio" *.py 2>/dev/null && ! grep -q "import temporalio" *.py 2>/dev/null; then + echo -e "${RED}✗${NC} Missing temporalio imports" + exit 1 +fi +echo -e "${GREEN}✓${NC} Has temporalio imports" + +# Check for signal/query decorators (optional but expected) +grep -q "@workflow.signal" workflows.py && echo -e "${GREEN}✓${NC} Contains @workflow.signal decorator" +grep -q "@workflow.query" workflows.py && echo -e "${GREEN}✓${NC} Contains @workflow.query decorator" + +echo "" +echo "Checking Python syntax..." + +SYNTAX_ERRORS=0 +for file in *.py; do + if [ -f "$file" ]; then + if python3 -m py_compile "$file" 2>/dev/null; then + echo -e "${GREEN}✓${NC} $file syntax is valid" + else + echo -e "${RED}✗${NC} $file has syntax errors" + python3 -m py_compile "$file" + SYNTAX_ERRORS=$((SYNTAX_ERRORS + 1)) + fi + fi +done + +if [ $SYNTAX_ERRORS -gt 0 ]; then + echo "" + echo -e "${RED}❌ Found syntax errors in $SYNTAX_ERRORS file(s)${NC}" + exit 1 +fi + +echo "" +echo "Checking dependencies..." + +if [ -f "requirements.txt" ]; then + if ! grep -q "temporalio" requirements.txt; then + echo -e "${RED}✗${NC} temporalio not found in requirements.txt" + exit 1 + fi + echo -e "${GREEN}✓${NC} temporalio dependency specified" +fi + +if [ -f "pyproject.toml" ]; then + if ! grep -q "temporalio" pyproject.toml; then + echo -e "${RED}✗${NC} temporalio not found in pyproject.toml" + exit 1 + fi + echo -e "${GREEN}✓${NC} temporalio dependency specified" +fi + +echo "" +echo "=========================================" +echo -e "${GREEN}✅ ALL VALIDATIONS PASSED${NC}" +echo "=========================================" diff --git a/test/typescript/.gitignore b/test/typescript/.gitignore new file mode 100644 index 0000000..592f86d --- /dev/null +++ b/test/typescript/.gitignore @@ -0,0 +1 @@ +test-workspace/ diff --git a/test/typescript/run-integration-test.sh b/test/typescript/run-integration-test.sh new file mode 100755 index 0000000..1b57ed2 --- /dev/null +++ b/test/typescript/run-integration-test.sh @@ -0,0 +1,65 @@ +#!/bin/bash +set -e + +# Load common functions +source "$(dirname "${BASH_SOURCE[0]}")/../lib/common.sh" + +setup_paths +print_header "Temporal TypeScript Skill Integration Test" + +# Common setup and validation +setup_workspace +check_claude_cli +check_api_key +generate_code +run_validation + +# TypeScript-specific execution test +start_execution_test + +# Install dependencies and build +echo -e "${YELLOW}Installing dependencies and building...${NC}" +npm install > /dev/null 2>&1 || true +npm run build > /dev/null 2>&1 || npx tsc > /dev/null 2>&1 || true + +# Start worker +echo -e "${YELLOW}Starting worker...${NC}" +if [ -f "dist/worker.js" ]; then + node dist/worker.js > worker.log 2>&1 & +elif [ -f "lib/worker.js" ]; then + node lib/worker.js > worker.log 2>&1 & +else + npx ts-node worker.ts > worker.log 2>&1 & +fi +WORKER_PID=$! +sleep 5 + +if ! kill -0 $WORKER_PID 2>/dev/null; then + echo -e "${RED}✗ Worker failed to start${NC}" + tail -20 worker.log + cleanup_temporal + exit 1 +fi +echo -e "${GREEN}✓ Worker is running${NC}" + +# Run client (with 30 second timeout) +echo -e "${YELLOW}Running client...${NC}" +if [ -f "dist/client.js" ]; then + CLIENT_CMD="node dist/client.js" +elif [ -f "lib/client.js" ]; then + CLIENT_CMD="node lib/client.js" +else + CLIENT_CMD="npx ts-node client.ts" +fi + +if timeout 30 $CLIENT_CMD TestUser 2>&1; then + echo -e "${GREEN}✓ Workflow executed successfully${NC}" + EXECUTION_SUCCESS=true +else + echo -e "${RED}✗ Workflow execution failed or timed out${NC}" + EXECUTION_SUCCESS=false +fi + +# Cleanup +kill $WORKER_PID 2>/dev/null || true +report_execution_result "$EXECUTION_SUCCESS" diff --git a/test/typescript/test-prompt.txt b/test/typescript/test-prompt.txt new file mode 100644 index 0000000..3b55967 --- /dev/null +++ b/test/typescript/test-prompt.txt @@ -0,0 +1,21 @@ +Create a complete Temporal workflow application in TypeScript that demonstrates a greeting workflow. + +Requirements: +1. Create a workflow that takes a name parameter and returns a greeting message +2. Create an activity that formats the greeting +3. Include a worker that registers the workflow and activity +4. Include a client that starts the workflow +5. Use proper async/await patterns +6. Include TypeScript types on all function signatures +7. Use the latest version of the @temporalio packages +8. Create these files in the current directory (not in a src/ subdirectory): + - workflows.ts + - activities.ts + - worker.ts + - client.ts + - package.json + - tsconfig.json +9. Add a signal handler to the workflow that can update the greeting style +10. Add a query handler to get the current greeting count + +The application should be production-ready with proper error handling and best practices. diff --git a/test/typescript/validate.sh b/test/typescript/validate.sh new file mode 100755 index 0000000..48a6999 --- /dev/null +++ b/test/typescript/validate.sh @@ -0,0 +1,121 @@ +#!/bin/bash +set -e + +GREEN='\033[0;32m' +RED='\033[0;31m' +YELLOW='\033[1;33m' +NC='\033[0m' + +echo "=========================================" +echo "Validating Generated TypeScript Application" +echo "=========================================" +echo "" + +# Check required files +echo "Checking file structure..." +REQUIRED_FILES=("workflows.ts" "activities.ts" "worker.ts" "client.ts") +MISSING_FILES=() + +for file in "${REQUIRED_FILES[@]}"; do + if [ ! -f "$file" ] && [ ! -f "src/$file" ]; then + MISSING_FILES+=("$file") + else + if [ -f "$file" ]; then + echo -e "${GREEN}✓${NC} $file exists" + else + echo -e "${GREEN}✓${NC} src/$file exists" + fi + fi +done + +# Check for package.json +if [ ! -f "package.json" ]; then + echo -e "${RED}✗${NC} Missing package.json" + MISSING_FILES+=("package.json") +else + echo -e "${GREEN}✓${NC} package.json exists" +fi + +# Check for tsconfig.json +if [ ! -f "tsconfig.json" ]; then + echo -e "${RED}✗${NC} Missing tsconfig.json" + MISSING_FILES+=("tsconfig.json") +else + echo -e "${GREEN}✓${NC} tsconfig.json exists" +fi + +if [ ${#MISSING_FILES[@]} -gt 0 ]; then + echo "" + echo -e "${RED}❌ Missing required files:${NC}" + for file in "${MISSING_FILES[@]}"; do + echo " - $file" + done + exit 1 +fi + +echo "" +echo "Checking code patterns..." + +# Find workflow file +WORKFLOW_FILE="workflows.ts" +[ -f "src/workflows.ts" ] && WORKFLOW_FILE="src/workflows.ts" + +# Check for proxyActivities (TypeScript pattern) +if grep -q "proxyActivities" "$WORKFLOW_FILE" 2>/dev/null; then + echo -e "${GREEN}✓${NC} Uses proxyActivities pattern" +else + echo -e "${YELLOW}!${NC} proxyActivities not found (may use different pattern)" +fi + +# Check for async/await +if ! grep -q "async" "$WORKFLOW_FILE" || ! grep -q "await" "$WORKFLOW_FILE"; then + echo -e "${RED}✗${NC} Missing async/await syntax in $WORKFLOW_FILE" + exit 1 +fi +echo -e "${GREEN}✓${NC} Uses async/await syntax" + +# Check for temporalio imports +ALL_TS_FILES=$(find . -name "*.ts" -not -path "./node_modules/*" 2>/dev/null) +if echo "$ALL_TS_FILES" | xargs grep -l "@temporalio" 2>/dev/null | head -1 > /dev/null; then + echo -e "${GREEN}✓${NC} Has @temporalio imports" +else + echo -e "${RED}✗${NC} Missing @temporalio imports" + exit 1 +fi + +# Check for signal/query (optional but expected) +grep -q "defineSignal" "$WORKFLOW_FILE" 2>/dev/null && echo -e "${GREEN}✓${NC} Contains defineSignal" +grep -q "defineQuery" "$WORKFLOW_FILE" 2>/dev/null && echo -e "${GREEN}✓${NC} Contains defineQuery" + +echo "" +echo "Checking TypeScript syntax..." + +if command -v npx &> /dev/null; then + if [ -f "package.json" ] && [ ! -d "node_modules" ]; then + echo "Installing dependencies..." + npm install > /dev/null 2>&1 || true + fi + + if npx tsc --noEmit 2>/dev/null; then + echo -e "${GREEN}✓${NC} TypeScript compilation successful" + else + echo -e "${YELLOW}!${NC} TypeScript compilation had issues (may need dependencies)" + fi +else + echo -e "${YELLOW}!${NC} npx not found, skipping TypeScript compilation check" +fi + +echo "" +echo "Checking dependencies..." + +if grep -q "@temporalio" package.json; then + echo -e "${GREEN}✓${NC} @temporalio dependencies specified" +else + echo -e "${RED}✗${NC} @temporalio not found in package.json" + exit 1 +fi + +echo "" +echo "=========================================" +echo -e "${GREEN}✅ ALL VALIDATIONS PASSED${NC}" +echo "========================================="