Skip to content

v0 Wave D: Decorator authoring layer - #46

Merged
ThePlenkov merged 6 commits into
v0-l-clifrom
v0-d-decorators
Aug 13, 2026
Merged

ThePlenkov merged 6 commits into
v0-l-clifrom
v0-d-decorators

Conversation

@ThePlenkov

@ThePlenkov ThePlenkov commented Aug 13, 2026 •

Copy link
Copy Markdown
Contributor

User description

Summary

  • New @sverka/decorators package — 3rd authoring surface (after Construct API and SDK)
  • Decorators: @pipeline, @step, @stepWithOptions, @entry, @input, @output
  • decoratePipeline(PipelineClass, project, id) creates a Pipeline construct from a decorated class
  • Metadata approach: Symbol-based per-class metadata (TC39 context.metadata pattern)
  • @step split into @step (bare) and @stepWithOptions (factory) to avoid TDZ issues under esbuild/vitest
  • Conformance verified: decorator-authored pipeline produces same Definition Graph as Construct API

Test plan

  • decorators: 11 tests (3 public-api + 8 decorators including conformance)
  • All 4 affected packages green: 102 tests (decorators 11, constructs 20, sdk 41, core 30)
  • typecheck/lint/build clean
  • No any types
  • Conformance: decorator pipeline → same graph as Construct API (step IDs, entry IDs match)

Generated with Devin


Summary by cubic

Adds @sverka/decorators, a TC39-standard decorator authoring layer that synthesizes the same Definition Graph as the Construct/SDK APIs. Removes pipeline-level @output; step outputs now come from StepOptions.outputs or StepBuilder.outputs().

Summary

  • Public API: @pipeline, @step, @step(options)/@stepWithOptions, @entry(trigger), @input, decoratePipeline(PipelineClass, project, id).
  • Method steps: methods may return a StepBuilder or use this.sh to compose commands joined with " && "; supports string/number/boolean/Reference interpolation and collects inputs.
  • Options parity: applies runtime, timeout, outputs, and dependsOn to both ShellStep and StepBuilder.
  • Metadata: shared per-class store on Symbol.for('sverka:pipeline:metadata') with fields at Symbol.for('sverka:fields'); decorators use context.metadata or addInitializer.
  • Validation and errors: input/options validation; errors include INVALID_FIELD, MISSING_INITIALIZER, INVALID_OPTIONS, DUPLICATE_FIELD, NOT_A_PIPELINE. Preserves source order and matches Construct/SDK graphs in specs/tests.

Migration

  • Replace any @output usage with StepOptions.outputs or StepBuilder.outputs(...).

Written for commit ab2ea85. Summary will update on new commits.

Review in cubic


CodeAnt-AI Description

Add a decorator-based way to author Sverka pipelines

What Changed

  • Added @sverka/decorators with @pipeline, @step, @stepWithOptions, @entry, and @input
  • Decorated classes can now create pipelines with shell commands, step builders, outputs, dependencies, triggers, and validated inputs
  • Step methods can return builders or combine multiple shell operations, including references to inputs and step outputs
  • Added clear validation errors for missing or invalid fields, options, inputs, duplicate decorators, and non-pipeline classes
  • Decorator-authored pipelines preserve source order and produce the same definition graph as Construct API pipelines
  • Added an active specification and coverage for the public API, supported authoring styles, validation, and graph conformance

Impact

✅ Decorator-authored pipelines
✅ Reusable step methods with output references
✅ Clearer pipeline authoring errors

💡 Usage Guide

Checking Your Pull Request

Every time you make a pull request, our system automatically looks through it. We check for security issues, mistakes in how you're setting up your infrastructure, and common code problems. We do this to make sure your changes are solid and won't cause any trouble later.

Talking to CodeAnt AI

Got a question or need a hand with something in your pull request? You can easily get in touch with CodeAnt AI right here. Just type the following in a comment on your pull request, and replace "Your question here" with whatever you want to ask:

@codeant-ai ask: Your question here

This lets you have a chat with CodeAnt AI about your pull request, making it easier to understand and improve your code.

Example

@codeant-ai ask: Can you suggest a safer alternative to storing this secret?

Preserve Org Learnings with CodeAnt

You can record team preferences so CodeAnt AI applies them in future reviews. Reply directly to the specific CodeAnt AI suggestion (in the same thread) and replace "Your feedback here" with your input:

@codeant-ai: Your feedback here

This helps CodeAnt AI learn and adapt to your team's coding style and standards.

Example

@codeant-ai: Do not flag unused imports.

Retrigger review

Ask CodeAnt AI to review the PR again, by typing:

@codeant-ai: review

Check Your Repository Health

To analyze the health of your code repository, visit our dashboard at https://app.codeant.ai. This tool helps you identify potential issues and areas for improvement in your codebase, ensuring your repository maintains high standards of code health.

@codeant-ai

codeant-ai Bot commented Aug 13, 2026 •

Copy link
Copy Markdown

🤖 CodeAnt AI — Review Status

Status Commit Started (UTC) Finished (UTC)
✅ Incremental review completed 139924b Aug 13, 2026 · 11:25 11:26
✅ Incremental review completed 422ccab Aug 13, 2026 · 10:12 10:13
✅ Incremental review completed 4d1fd49 Aug 13, 2026 · 08:23 08:23
✅ Reviewed your PR 06b63e4 Aug 13, 2026 · 01:05 01:07

@cubic-dev-ai

cubic-dev-ai Bot commented Aug 13, 2026

Copy link
Copy Markdown

Running ultrareview automatically — This PR introduces a new public decorator authoring layer with metadata-based pipeline synthesis, a large new package (~845 lines) that could hide subtle bugs in decorator semantics, metadata handling, and graph construction affecting end users.. I'll post findings when complete.

@cubic-dev-ai

cubic-dev-ai Bot commented Aug 13, 2026

Copy link
Copy Markdown

I can't run this ultrareview because you've reached your trial's review limit. Trial plans have lower review limits than paid plans. Upgrade now to resume reviews.

To help optimise your usage, you can tune cubic to get the most out of your usage limits:

Learn more →

@coderabbitai

coderabbitai Bot commented Aug 13, 2026 •

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: fb7fd147-5a94-4d9a-8bb5-ee2b3e96b319

📥 Commits

Reviewing files that changed from the base of the PR and between 139924b and bf5c827.

📒 Files selected for processing (1)
  • packages/decorators/src/synthesize.ts
📜 Recent review details
⏰ Context from checks skipped due to timeout. (1)
  • GitHub Check: Codacy Static Code Analysis
⚠️ CI failures not shown inline (2)

GitHub Actions: CI / 0_main.txt: v0 Wave D: Decorator authoring layer

Conclusion: failure

View job details

##[group]❌ > nx run sdk:test
 > bun run vitest run --passWithNoTests
 �[1m�[46m RUN �[49m�[22m �[36mv3.2.7 �[39m�[90m/home/runner/work/sverka/sverka/packages/sdk�[39m
  �[32m✓�[39m src/__tests__/context.test.ts �[2m(�[22m�[2m14 tests�[22m�[2m)�[22m�[32m 34�[2mms�[22m�[39m
  �[32m✓�[39m src/__tests__/sh.test.ts �[2m(�[22m�[2m8 tests�[22m�[2m)�[22m�[32m 21�[2mms�[22m�[39m
  �[32m✓�[39m src/__tests__/pipeline.test.ts �[2m(�[22m�[2m2 tests�[22m�[2m)�[22m�[32m 24�[2mms�[22m�[39m
  �[32m✓�[39m src/__tests__/public-api.test.ts �[2m(�[22m�[2m3 tests�[22m�[2m)�[22m�[32m 28�[2mms�[22m�[39m
  �[32m✓�[39m src/__tests__/images.test.ts �[2m(�[22m�[2m6 tests�[22m�[2m)�[22m�[32m 25�[2mms�[22m�[39m
  �[32m✓�[39m src/__tests__/errors.test.ts �[2m(�[22m�[2m2 tests�[22m�[2m)�[22m�[32m 11�[2mms�[22m�[39m
  �[32m✓�[39m src/__tests__/when.test.ts �[2m(�[22m�[2m2 tests�[22m�[2m)�[22m�[32m 6�[2mms�[22m�[39m
  �[32m✓�[39m src/__tests__/artifact.test.ts �[2m(�[22m�[2m2 tests�[22m�[2m)�[22m�[32m 6�[2mms�[22m�[39m
 �[31m⎯⎯⎯⎯⎯⎯�[39m�[1m�[41m Failed Suites 1 �[49m�[22m�[31m⎯⎯⎯⎯⎯⎯⎯�[39m
 �[41m�[1m FAIL �[22m�[49m src/__tests__/conformance.test.ts�[2m [ src/__tests__/conformance.test.ts ]�[22m
 �[31m�[1mError�[22m: Cannot find package '`@sverka/core`' imported from '/home/runner/work/sverka/sverka/packages/sdk/src/__tests__/conformance.test.ts'�[39m
 �[36m �[2m❯�[22m src/__tests__/conformance.test.ts:�[2m7:1�[22m�[39m
     �[90m  5| �[39m�[35mimport�[39m { describe�[33m,�[39m it�[33m,�[39m expect } �[35mfrom�[39m �[32m"vitest"�[39m�[33m;�[39m
     �[90m  6| �[39mimport { Project, Pipeline, ShellStep, Entry, push } from "`@sverka/con`…
     �[90m  7| �[39m�[35mimport�[39m { synthesize�[33m,�[39m type �[33mDefinitionGraph�[39m } �[35mfrom�[39m �[32m"`@sverka/core`"�[39m�[33m;�[39m
     �[90m   | �[39m�[31m^�[39m
     �[90m  8| �[39m�[35mimport�[39m { sh�[33m,�[39m artifact�[33m,�[39m pipeline } �[35mfrom�[39m �[32m"../index.js"�[39m�[33m;�[39m
     �[90m  9| �[39m
 �[31m�[1mCaused by: Error�[22m: Failed...

GitHub Actions: CI / main: v0 Wave D: Decorator authoring layer

Conclusion: failure

View job details

##[group]❌ > nx run sdk:test
 > bun run vitest run --passWithNoTests
 �[1m�[46m RUN �[49m�[22m �[36mv3.2.7 �[39m�[90m/home/runner/work/sverka/sverka/packages/sdk�[39m
  �[32m✓�[39m src/__tests__/context.test.ts �[2m(�[22m�[2m14 tests�[22m�[2m)�[22m�[32m 34�[2mms�[22m�[39m
  �[32m✓�[39m src/__tests__/sh.test.ts �[2m(�[22m�[2m8 tests�[22m�[2m)�[22m�[32m 21�[2mms�[22m�[39m
  �[32m✓�[39m src/__tests__/pipeline.test.ts �[2m(�[22m�[2m2 tests�[22m�[2m)�[22m�[32m 24�[2mms�[22m�[39m
  �[32m✓�[39m src/__tests__/public-api.test.ts �[2m(�[22m�[2m3 tests�[22m�[2m)�[22m�[32m 28�[2mms�[22m�[39m
  �[32m✓�[39m src/__tests__/images.test.ts �[2m(�[22m�[2m6 tests�[22m�[2m)�[22m�[32m 25�[2mms�[22m�[39m
  �[32m✓�[39m src/__tests__/errors.test.ts �[2m(�[22m�[2m2 tests�[22m�[2m)�[22m�[32m 11�[2mms�[22m�[39m
  �[32m✓�[39m src/__tests__/when.test.ts �[2m(�[22m�[2m2 tests�[22m�[2m)�[22m�[32m 6�[2mms�[22m�[39m
  �[32m✓�[39m src/__tests__/artifact.test.ts �[2m(�[22m�[2m2 tests�[22m�[2m)�[22m�[32m 6�[2mms�[22m�[39m
 �[31m⎯⎯⎯⎯⎯⎯�[39m�[1m�[41m Failed Suites 1 �[49m�[22m�[31m⎯⎯⎯⎯⎯⎯⎯�[39m
 �[41m�[1m FAIL �[22m�[49m src/__tests__/conformance.test.ts�[2m [ src/__tests__/conformance.test.ts ]�[22m
 �[31m�[1mError�[22m: Cannot find package '`@sverka/core`' imported from '/home/runner/work/sverka/sverka/packages/sdk/src/__tests__/conformance.test.ts'�[39m
 �[36m �[2m❯�[22m src/__tests__/conformance.test.ts:�[2m7:1�[22m�[39m
     �[90m  5| �[39m�[35mimport�[39m { describe�[33m,�[39m it�[33m,�[39m expect } �[35mfrom�[39m �[32m"vitest"�[39m�[33m;�[39m
     �[90m  6| �[39mimport { Project, Pipeline, ShellStep, Entry, push } from "`@sverka/con`…
     �[90m  7| �[39m�[35mimport�[39m { synthesize�[33m,�[39m type �[33mDefinitionGraph�[39m } �[35mfrom�[39m �[32m"`@sverka/core`"�[39m�[33m;�[39m
     �[90m   | �[39m�[31m^�[39m
     �[90m  8| �[39m�[35mimport�[39m { sh�[33m,�[39m artifact�[33m,�[39m pipeline } �[35mfrom�[39m �[32m"../index.js"�[39m�[33m;�[39m
     �[90m  9| �[39m
 �[31m�[1mCaused by: Error�[22m: Failed...
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx}: - No any: Use unknown and narrow. Strict TypeScript.

  • Error handling: Custom error classes per package.

Files:

  • packages/decorators/src/synthesize.ts
🔇 Additional comments (1)
packages/decorators/src/synthesize.ts (1)

217-218: LGTM!


📝 Walkthrough

Summary by CodeRabbit

  • New Features

    • Added decorator-based pipeline authoring for pipelines, steps, entries, and inputs.
    • Added configurable step options, including runtime, timeout, outputs, and dependencies.
    • Added pipeline synthesis from decorated classes, preserving declaration order and supporting method-based steps.
    • Added structured decorator errors with validation codes.
    • Published the decorators package with a complete public API.
  • Documentation

    • Added a specification covering decorator usage, behavior, validation, and API requirements.
  • Tests

    • Added coverage for decorator behavior, pipeline generation, ordering, validation, and public exports.

Walkthrough

Added @sverka/decorators with TC39 pipeline, step, entry, and input decorators. Added metadata registration, pipeline synthesis, validation errors, public exports, package configuration, tests, and an active authoring specification.

Changes

Decorator Pipeline Authoring

Layer / File(s) Summary
Decorator contracts and specification
packages/decorators/src/types.ts, packages/decorators/src/errors.ts, specs/04-authoring-decorators/spec.md
Defines decorator metadata, step options, planning context, entry targets, input values, error codes, supported values, and validation cases.
Decorator metadata registration
packages/decorators/src/decorators.ts
Registers pipeline, step, entry, and input metadata. Preserves decorated methods, detects duplicate fields, and validates step options.
Decorated pipeline synthesis
packages/decorators/src/synthesize.ts, packages/decorators/src/__tests__/decorators.test.ts
Instantiates decorated classes, validates inputs, creates steps and entries in source order, evaluates method-based steps, interpolates references, and reports validation errors.
Package wiring and public API
packages/decorators/package.json, packages/decorators/tsconfig.json, packages/decorators/src/index.ts, packages/decorators/src/__tests__/public-api.test.ts
Adds package configuration, TypeScript settings, public exports, and API conformance tests.

Estimated code review effort: 4 (Complex) | ~45 minutes

Mergeability Score: 🟡 Moderate · up to bf5c8

The new decorator authoring path can reject a valid second synthesis of the same class and accept malformed entry definitions, which may lead to failed pipeline creation or invalid graphs. Merge readiness is moderate until these bounded correctness issues are fixed or explicitly accepted by the owner.

Sequence Diagram(s)

sequenceDiagram
  participant DecoratedClass
  participant decoratePipeline
  participant Project
  participant Pipeline
  participant ShellStep
  participant Entry
  DecoratedClass->>decoratePipeline: instantiate and read decorator metadata
  decoratePipeline->>Project: create pipeline construct
  decoratePipeline->>Pipeline: collect inputs and process fields in source order
  decoratePipeline->>ShellStep: synthesize string, builder, or method-based steps
  decoratePipeline->>Entry: synthesize validated entry targets and triggers
Loading

Possibly related PRs

  • sverka-dev/sverka#1: Provides the core Pipeline, StepBuilder, and Entry APIs used by decorator synthesis.
  • sverka-dev/sverka#37: Defines the authoring-decorators architecture implemented by this package.
  • sverka-dev/sverka#38: Provides the Project, Pipeline, ShellStep, and Entry constructs consumed during synthesis.

Suggested labels: baz: needs review

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 40.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description check ✅ Passed The description clearly explains the new decorator package, APIs, synthesis behavior, validation, testing, and migration impact.
Title check ✅ Passed The title is concise and accurately identifies the decorator authoring layer added by the pull request.
✨ Finishing Touches 💡 2
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🛠️ Fix failing CI checks 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch v0-d-decorators

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

@codeant-ai codeant-ai Bot added the size:XL This PR changes 500-999 lines, ignoring generated files label Aug 13, 2026
@baz-reviewer

baz-reviewer Bot commented Aug 13, 2026 •

Copy link
Copy Markdown

Merger

Needs Review

Fallback decorator metadata registration is not idempotent: a second decoratePipeline call on the same class re-runs initializers and throws DUPLICATE_FIELD in runtimes without Symbol.metadata. This is an untested correctness issue in a new public API, compounded by no CI run.

Commit ab2ea85 · Evaluated 2026-08-13 21:38 UTC

Review this PR on Baz | Customize your next review

@amazon-q-developer amazon-q-developer Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Review Summary

This PR introduces a new decorator authoring layer for Sverka pipelines with comprehensive test coverage. While the implementation demonstrates good architectural design and proper TC39 decorator usage, there are 5 critical defects that must be addressed before merge:

Critical Issues (Must Fix)

  1. Null pointer risk in pipeline decorator - Non-null assertion on context.metadata! can store undefined, causing silent failures
  2. Unhandled constructor errors - Pipeline class instantiation lacks error handling, leading to unclear crash behavior
  3. Unsafe method execution - User methods execute arbitrary code without isolation during synthesis
  4. Type safety violation - Duck typing with "type" in value accepts invalid Input objects
  5. Dead code - Unused registerInputOnMetadata function creates maintenance burden

Test Coverage

All 11 tests pass with good conformance validation, but runtime error handling paths remain untested.

Recommendation: Address the 5 critical defects before merging to prevent runtime failures and security risks in production.


You can now have the agent implement changes and create commits directly on your pull request's source branch. Simply comment with /q followed by your request in natural language to ask the agent to make changes.

Comment thread packages/decorators/src/decorators.ts Outdated
Comment thread packages/decorators/src/synthesize.ts Outdated
Comment thread packages/decorators/src/synthesize.ts Outdated
Comment thread packages/decorators/src/decorators.ts Outdated
Comment thread packages/decorators/src/synthesize.ts Outdated
@codacy-production

codacy-production Bot commented Aug 13, 2026 •

Copy link
Copy Markdown

Up to standards ✅

🟢 Issues 0 issues

Results:
0 new issues

View in Codacy

🟢 Metrics 2 duplication

Metric Results
Duplication 2

View in Codacy

AI Reviewer: first review requested successfully. AI can make mistakes. Always validate suggestions.

Run reviewer

TIP This summary will be updated as you push new changes.

@qodo-code-review

Copy link
Copy Markdown

PR Summary by Qodo

Add @sverka/decorators authoring layer (TC39 decorators)

✨ Enhancement 🧪 Tests 📝 Documentation ⚙️ Configuration changes 🕐 40+ Minutes

Grey Divider

AI Description

• Introduce new @sverka/decorators package for authoring pipelines via TC39 decorators.
• Add decoratePipeline() to synthesize decorated classes into Constructs-based pipelines.
• Add conformance + API tests ensuring decorator pipelines match Construct API graphs.
Diagram

graph TD
  A([Pipeline author]) --> B["Decorated pipeline class"] --> C[("Per-class metadata")]
  C --> D["decoratePipeline()"] --> E["@sverka/constructs (Pipeline/Steps/Entry)"] --> F["@sverka/core synthesize()"] --> G[("Definition Graph")]

  subgraph Legend
    direction LR
    _actor([Actor]) ~~~ _comp["Component/Function"] ~~~ _store[(Store/Artifact)]
  end
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Use experimentalDecorators + reflect-metadata
  • ➕ Mature ecosystem patterns and examples
  • ➕ Can avoid instantiating the class to read some metadata
  • ➖ Contradicts the stated goal of TC39 standard decorators
  • ➖ Adds runtime dependency and potentially leaks design-time types into runtime
  • ➖ Harder to make portable across runtimes (Bun/Node) and bundlers
2. Static registry on the class (no context.metadata)
  • ➕ Simpler mental model: class fields push into ClassName.__sverkaRegistry
  • ➕ No reliance on decorator metadata semantics
  • ➖ More boilerplate and easier for users to accidentally mutate/overwrite
  • ➖ Harder to ensure per-class isolation across inheritance/rewrites
  • ➖ Less aligned with TC39 direction and future Symbol.metadata support
3. Codegen/compile-time transform from decorated classes
  • ➕ No runtime class instantiation required; can detect invalid patterns at build time
  • ➕ Potentially richer features (forward refs, validation)
  • ➖ Significantly higher complexity (build integration, source maps, tooling)
  • ➖ Harder to keep the authoring surface runtime-agnostic and lightweight

Recommendation: The current approach (TC39 decorators + symbol-attached per-class metadata + runtime synthesis via decoratePipeline) is the best fit for v0: it avoids experimentalDecorators/reflect-metadata, stays portable, and keeps the authoring surface lightweight while still proving conformance via graph-level tests. The main tradeoff—instantiating the pipeline class to read initializers—is acceptable for v0 and matches the stated spec/constraints.

Files changed (12) +834 / -11

Enhancement (5) +417 / -0
decorators.tsImplement TC39 decorators and metadata recording +180/-0

Implement TC39 decorators and metadata recording

• Implements @pipeline, @step (bare), @stepWithOptions (factory), @entry, @input, and @output using TC39 standard decorators and context.metadata. Stores per-class metadata behind a symbol on the constructor and records decorated fields (and options/trigger) in insertion/source order with validation and duplicate detection.

packages/decorators/src/decorators.ts

errors.tsDefine DecoratorError and error codes +20/-0

Define DecoratorError and error codes

• Adds a dedicated error type with stable error codes for invalid fields/options, missing initializers, duplicates, and non-pipeline usage, including an explicit (readonly) cause field.

packages/decorators/src/errors.ts

index.tsExpose decorators package public API +6/-0

Expose decorators package public API

• Exports the decorator functions, decoratePipeline entrypoint, public types, and DecoratorError symbols as the package’s main API surface.

packages/decorators/src/index.ts

synthesize.tsImplement decoratePipeline() synthesis into Constructs +189/-0

Implement decoratePipeline() synthesis into Constructs

• Instantiates decorated pipeline classes, reads recorded field metadata, collects @input values from instance initializers, and creates Pipeline/ShellStep/Entry constructs in source order. Supports step values as string shorthand or StepBuilder; validates entry fields and throws DecoratorError for invalid/missing data.

packages/decorators/src/synthesize.ts

types.tsAdd public decorator types (StepOptions, FieldMetadata) +22/-0

Add public decorator types (StepOptions, FieldMetadata)

• Defines the type model for decorator metadata including step options (runtime/timeout/outputs/dependsOn), entry targets, and field kinds used across decorators and synthesis.

packages/decorators/src/types.ts

Refactor (1) +4 / -0
registry.tsAdd registry re-exports for metadata helpers +4/-0

Add registry re-exports for metadata helpers

• Provides a small re-export layer for internal metadata accessors used by synthesis (or future integrations).

packages/decorators/src/registry.ts

Tests (2) +228 / -0
decorators.test.tsAdd decorator behavior + conformance tests +179/-0

Add decorator behavior + conformance tests

• Covers @step string shorthand, @stepWithOptions timeout, StepBuilder (sh) usage, @entry roots/trigger behavior, @input registration, source-order step creation, and graph conformance vs Construct API. Includes negative test for calling decoratePipeline without @pipeline.

packages/decorators/src/tests/decorators.test.ts

public-api.test.tsAdd public API export surface tests +49/-0

Add public API export surface tests

• Verifies all decorator functions and decoratePipeline are exported, DecoratorError shape is correct, and key public types are importable (compile-time check).

packages/decorators/src/tests/public-api.test.ts

Documentation (1) +130 / -11
spec.mdWrite Spec 04 for decorator authoring surface +130/-11

Write Spec 04 for decorator authoring surface

• Promotes Spec 04 from stub to active with goals/non-goals, API examples, metadata model, error codes, and an explicit test plan including conformance requirements.

specs/04-authoring-decorators/spec.md

Other (3) +55 / -0
bun.lockRegister @sverka/decorators workspace package +16/-0

Register @sverka/decorators workspace package

• Adds the new decorators package to the Bun lockfile/workspace map with its internal dependencies on @sverka/constructs and @sverka/sdk and dev dependencies for build/test/typecheck.

bun.lock

package.jsonAdd @sverka/decorators package manifest +31/-0

Add @sverka/decorators package manifest

• Introduces the new workspace package with ESM exports, build/test/lint/typecheck scripts, and dependencies on constructs + sdk (and core for tests).

packages/decorators/package.json

tsconfig.jsonAdd package TypeScript config +8/-0

Add package TypeScript config

• Configures the decorators package build/typecheck settings (rootDir/outDir) extending the repo base tsconfig.

packages/decorators/tsconfig.json

Comment thread packages/decorators/src/synthesize.ts Outdated
Comment thread packages/decorators/src/synthesize.ts
Comment thread packages/decorators/src/synthesize.ts
Comment thread packages/decorators/src/decorators.ts Outdated
Comment thread packages/decorators/src/decorators.ts Outdated
Comment thread packages/decorators/src/decorators.ts Outdated

@codacy-production codacy-production Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull Request Overview

This PR introduces the decorator-based authoring layer, but several key features are non-functional or unaddressed. Most notably, the @output decorator is currently a 'no-op' as the synthesis logic completely ignores output metadata. Additionally, the implementation for method-based steps is logically unreachable and type-restricted, which directly contradicts the acceptance criteria.

Codacy analysis indicates the PR is not up to standards. The synthesis engine ('synthesize.ts') exhibits high complexity and code duplication between the string-shorthand and method-planning paths. Several validation scenarios and the entirety of the @output functionality lack test coverage. These architectural and logical issues should be resolved before merging to ensure the authoring layer behaves as specified.

About this PR

  • The synthesis engine is currently incomplete. Metadata for @output is collected via decorators but is never evaluated or applied during the decoratePipeline synthesis process.
  • There is a systemic misalignment between the decorator definitions and the synthesizer regarding method-based steps. The decorators are typed only for fields, while the synthesizer contains (currently broken) logic for methods.

Test suggestions

  • @step string shorthand creates a ShellStep with the correct command
  • @stepWithOptions correctly applies timeout and other options to the step
  • @step with SDK StepBuilder (sh...) correctly builds the step
  • @step as a method decorator for planning multiple operations
  • @entry correctly registers triggers and root step IDs
  • @input registers pipeline-level input parameters
  • @output registers pipeline-level output parameters
  • decoratePipeline throws NOT_A_PIPELINE for classes missing the @pipeline decorator
  • Validation error: duplicate field decorators on the same class
  • Validation error: @entry field initializer is not an array of strings
  • Unit test for sh template handler with non-string interpolations
Prompt proposal for missing tests
Consider implementing these tests if applicable:
1. @step as a method decorator for planning multiple operations
2. @output registers pipeline-level output parameters
3. Validation error: duplicate field decorators on the same class
4. Validation error: @entry field initializer is not an array of strings
5. Unit test for `sh` template handler with non-string interpolations

TIP Improve review quality by adding custom instructions
TIP How was this review? Give us feedback

Comment thread packages/decorators/src/synthesize.ts Outdated
Comment thread packages/decorators/src/synthesize.ts Outdated
Comment thread packages/decorators/src/synthesize.ts Outdated
Comment thread packages/decorators/src/decorators.ts Outdated
Comment thread packages/decorators/src/decorators.ts

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 10

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

Inline comments:
In `@packages/decorators/src/__tests__/decorators.test.ts`:
- Around line 155-165: Replace the partial pipeline length and step/entry ID
assertions in the definition graph comparison test with a complete deep-equality
assertion using expect(graph1).toEqual(graph2), ensuring all graph properties
are compared.

In `@packages/decorators/src/__tests__/public-api.test.ts`:
- Around line 43-47: Remove the tautological runtime assertions for
_opts.timeout, _target, _meta.kind, _kind, and _code in the public API test.
Keep the case as a compile-time-only type check, or replace the literal
comparisons with an assertion that validates the exported types.

In `@packages/decorators/src/decorators.ts`:
- Around line 170-180: Refactor createStepFromField to reduce cognitive
complexity by extracting focused helpers for field-value classification, builder
synthesis, and method synthesis. Keep each helper responsible for one stage and
preserve the existing behavior and output of createStepFromField.
- Around line 12-14: Update FIELDS_KEY in packages/decorators/src/decorators.ts
lines 12-14 and packages/decorators/src/synthesize.ts lines 11-12 to use the
shared Symbol.for("sverka:fields") metadata key instead of a string, preserving
the same key consistently in both files.
- Around line 20-25: Update the pipeline decorator around pipeline and
getPipelineMetadata so each class receives usable per-class metadata when
Symbol.metadata is unavailable. Initialize the Symbol.metadata polyfill before
decoration or use an equivalent per-class registry, and ensure pipeline stores
and getPipelineMetadata retrieves that same metadata object instead of
undefined.
- Around line 58-63: The step and stepWithOptions decorators must support method
contexts in addition to field contexts. Update both decorators to accept method
contexts and process function-valued steps before the invalid-value branch, then
update the planning context in synthesize to expose bare sh calls that record
commands alongside this.sh. Add coverage for an optioned step method asserting
the joined shell command; update packages/decorators/src/decorators.ts:58-63 and
packages/decorators/src/synthesize.ts:110-135 accordingly.

In `@packages/decorators/src/synthesize.ts`:
- Around line 103-106: Update the StepBuilder handling in the value synthesis
path to apply the field’s StepOptions—runtime, timeout, outputs, and
dependsOn—to the builder before invoking build(pipeline, name). Preserve
existing behavior for other field values, and add coverage for
`@stepWithOptions`(...) applied to a builder-valued field.
- Around line 41-46: Update the input-field handling in synthesize so every
`@input` field is validated instead of silently omitted: reject undefined, null,
missing type, or invalid type values by throwing DecoratorError with code
INVALID_FIELD, and only assign valid values to inputs[name].
- Around line 63-67: The input/output cases in the synthesis switch currently
discard `@output` metadata, so either implement end-to-end pipeline output storage
and synthesis through decoratePipeline and Pipeline, or remove `@output` from the
public decorator API and specification until supported. Keep the chosen behavior
consistent across decorator definitions, pipeline handling, and core synthesis.

In `@specs/04-authoring-decorators/spec.md`:
- Around line 149-150: Update the `@step` without initializer test-plan entry to
expect `MISSING_INITIALIZER` instead of `INVALID_FIELD`, matching the error
thrown by `createStepFromField`; leave the `decoratePipeline` case unchanged.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

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

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 82846138-3607-42e5-b0bb-aca97b7e4c51

📥 Commits

Reviewing files that changed from the base of the PR and between 17c5892 and 06b63e4.

⛔ Files ignored due to path filters (1)
  • bun.lock is excluded by !**/*.lock
📒 Files selected for processing (11)
  • packages/decorators/package.json
  • packages/decorators/src/__tests__/decorators.test.ts
  • packages/decorators/src/__tests__/public-api.test.ts
  • packages/decorators/src/decorators.ts
  • packages/decorators/src/errors.ts
  • packages/decorators/src/index.ts
  • packages/decorators/src/registry.ts
  • packages/decorators/src/synthesize.ts
  • packages/decorators/src/types.ts
  • packages/decorators/tsconfig.json
  • specs/04-authoring-decorators/spec.md
📜 Review details
⏰ Context from checks skipped due to timeout. (2)
  • GitHub Check: Codacy Static Code Analysis
  • GitHub Check: Amazon Q Developer
⚠️ CI failures not shown inline (2)

GitHub Actions: CI / main: v0 Wave D: Decorator authoring layer

Conclusion: failure

View job details

##[group]✅ > nx run checks:build
 > bun run tsdown
 �[34mℹ�[39m �[34mtsdown v0.22.14�[39m powered by �[38;2;255;126;23mrolldown v1.2.3�[39m
 �[34mℹ�[39m config file: �[4m/home/runner/work/sverka/sverka/packages/checks/tsdown.config.ts�[24m
 �[34mℹ�[39m entry: �[34msrc/index.ts�[39m
 �[34mℹ�[39m tsconfig: �[34mtsconfig.json�[39m
 �[34mℹ�[39m Build start
 �[34mℹ�[39m �[2mdist/�[22m�[1mindex.mjs�[22m        �[2m 7.87 kB�[22m �[2m│ gzip: 2.34 kB�[22m
 �[34mℹ�[39m �[2mdist/�[22mindex.mjs.map    �[2m15.70 kB�[22m �[2m│ gzip: 4.27 kB�[22m
 �[34mℹ�[39m �[2mdist/�[22mindex.d.mts.map  �[2m 0.46 kB�[22m �[2m│ gzip: 0.29 kB�[22m
 �[34mℹ�[39m �[2mdist/�[22m�[32m�[1mindex.d.mts�[22m�[39m      �[2m 2.70 kB�[22m �[2m│ gzip: 1.05 kB�[22m
 �[34mℹ�[39m 4 files, total: 26.73 kB
 �[32m✔�[39m Build complete in �[32m1516ms�[39m
 ##[endgroup]
  NX   Running target build for 18 projects failed
 Tasks not run because their dependencies failed or --nx-bail=true:
 - runtime-docker:build
 - runtime-host:build
 - cli:build
 Failed tasks:
 - engine-native:build
  NX   Nx Cloud wasn't able to store artifacts to the remote cache.
  NX   Nx Cloud encountered some problems
 This Nx Cloud organization has been disabled due to exceeding the FREE plan.
 Your organization can be re-enabled immediately by an organization admin upgrading to the Team plan at https://cloud.nx.app/orgs/6a7a1e77cff5d2abcf16725d/plans. (code: 401)
 ##[error]Process completed with exit code 130.

GitHub Actions: CI / 0_main.txt: v0 Wave D: Decorator authoring layer

Conclusion: failure

View job details

##[group]✅ > nx run checks:build
 > bun run tsdown
 �[34mℹ�[39m �[34mtsdown v0.22.14�[39m powered by �[38;2;255;126;23mrolldown v1.2.3�[39m
 �[34mℹ�[39m config file: �[4m/home/runner/work/sverka/sverka/packages/checks/tsdown.config.ts�[24m
 �[34mℹ�[39m entry: �[34msrc/index.ts�[39m
 �[34mℹ�[39m tsconfig: �[34mtsconfig.json�[39m
 �[34mℹ�[39m Build start
 �[34mℹ�[39m �[2mdist/�[22m�[1mindex.mjs�[22m        �[2m 7.87 kB�[22m �[2m│ gzip: 2.34 kB�[22m
 �[34mℹ�[39m �[2mdist/�[22mindex.mjs.map    �[2m15.70 kB�[22m �[2m│ gzip: 4.27 kB�[22m
 �[34mℹ�[39m �[2mdist/�[22mindex.d.mts.map  �[2m 0.46 kB�[22m �[2m│ gzip: 0.29 kB�[22m
 �[34mℹ�[39m �[2mdist/�[22m�[32m�[1mindex.d.mts�[22m�[39m      �[2m 2.70 kB�[22m �[2m│ gzip: 1.05 kB�[22m
 �[34mℹ�[39m 4 files, total: 26.73 kB
 �[32m✔�[39m Build complete in �[32m1516ms�[39m
 ##[endgroup]
  NX   Running target build for 18 projects failed
 Tasks not run because their dependencies failed or --nx-bail=true:
 - runtime-docker:build
 - runtime-host:build
 - cli:build
 Failed tasks:
 - engine-native:build
  NX   Nx Cloud wasn't able to store artifacts to the remote cache.
  NX   Nx Cloud encountered some problems
 This Nx Cloud organization has been disabled due to exceeding the FREE plan.
 Your organization can be re-enabled immediately by an organization admin upgrading to the Team plan at https://cloud.nx.app/orgs/6a7a1e77cff5d2abcf16725d/plans. (code: 401)
 ##[error]Process completed with exit code 130.
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx}: - No any: Use unknown and narrow. Strict TypeScript.

  • Error handling: Custom error classes per package.

Files:

  • packages/decorators/src/types.ts
  • packages/decorators/src/errors.ts
  • packages/decorators/src/__tests__/decorators.test.ts
  • packages/decorators/src/registry.ts
  • packages/decorators/src/__tests__/public-api.test.ts
  • packages/decorators/src/synthesize.ts
  • packages/decorators/src/index.ts
  • packages/decorators/src/decorators.ts
**/src/index.ts

📄 CodeRabbit inference engine (AGENTS.md)

  • Public API: Everything public is exported from src/index.ts.

Files:

  • packages/decorators/src/index.ts
🧠 Learnings (3)
📚 Learning: 2026-08-12T07:24:02.495Z
Learnt from: CR
Repo: sverka-dev/sverka PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-08-12T07:24:02.495Z
Learning: Applies to **/*.{ts,tsx} : - **Error handling:** Custom error classes per package.

Applied to files:

  • packages/decorators/tsconfig.json
  • packages/decorators/src/errors.ts
📚 Learning: 2026-08-12T07:24:02.495Z
Learnt from: CR
Repo: sverka-dev/sverka PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-08-12T07:24:02.495Z
Learning: Applies to **/src/index.ts : - **Public API:** Everything public is exported from `src/index.ts`.

Applied to files:

  • packages/decorators/tsconfig.json
  • packages/decorators/src/__tests__/public-api.test.ts
  • packages/decorators/src/index.ts
📚 Learning: 2026-08-12T07:24:02.495Z
Learnt from: CR
Repo: sverka-dev/sverka PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-08-12T07:24:02.495Z
Learning: Applies to **/*.{ts,tsx} : - **No `any`:** Use `unknown` and narrow. Strict TypeScript.

Applied to files:

  • packages/decorators/tsconfig.json
🪛 GitHub Check: SonarCloud Code Analysis
packages/decorators/src/__tests__/decorators.test.ts

[warning] 155-155: Prefer "expect(graph1.project.pipelines).toHaveLength(graph2.project.pipelines.length)" over this generic assertion for better reporting; it works on any object with a numeric length property.

See more on https://sonarcloud.io/project/issues?id=sverka-dev_sverka&issues=AZ_4p1RSH48vEq4FmFnU&open=AZ_4p1RSH48vEq4FmFnU&pullRequest=46

packages/decorators/src/__tests__/public-api.test.ts

[warning] 46-46: Replace this assertion; it always succeeds.

See more on https://sonarcloud.io/project/issues?id=sverka-dev_sverka&issues=AZ_4p1NFH48vEq4FmFnS&open=AZ_4p1NFH48vEq4FmFnS&pullRequest=46


[warning] 47-47: Replace this assertion; it always succeeds.

See more on https://sonarcloud.io/project/issues?id=sverka-dev_sverka&issues=AZ_4p1NFH48vEq4FmFnT&open=AZ_4p1NFH48vEq4FmFnT&pullRequest=46

packages/decorators/src/synthesize.ts

[warning] 93-93: Either remove this useless object instantiation of "ShellStep" or use it.

See more on https://sonarcloud.io/project/issues?id=sverka-dev_sverka&issues=AZ_4p1RdH48vEq4FmFnW&open=AZ_4p1RdH48vEq4FmFnW&pullRequest=46


[warning] 127-127: Either remove this useless object instantiation of "ShellStep" or use it.

See more on https://sonarcloud.io/project/issues?id=sverka-dev_sverka&issues=AZ_4p1RdH48vEq4FmFnX&open=AZ_4p1RdH48vEq4FmFnX&pullRequest=46


[warning] 177-177: 'unknown' overrides all other types in this union type.

See more on https://sonarcloud.io/project/issues?id=sverka-dev_sverka&issues=AZ_4p1RdH48vEq4FmFnZ&open=AZ_4p1RdH48vEq4FmFnZ&pullRequest=46


[warning] 168-168: Either remove this useless object instantiation of "Entry" or use it.

See more on https://sonarcloud.io/project/issues?id=sverka-dev_sverka&issues=AZ_4p1RdH48vEq4FmFnY&open=AZ_4p1RdH48vEq4FmFnY&pullRequest=46


[failure] 83-83: Refactor this function to reduce its Cognitive Complexity from 29 to the 15 allowed.

See more on https://sonarcloud.io/project/issues?id=sverka-dev_sverka&issues=AZ_4p1RdH48vEq4FmFnV&open=AZ_4p1RdH48vEq4FmFnV&pullRequest=46

🔇 Additional comments (9)
packages/decorators/src/types.ts (1)

3-22: LGTM!

packages/decorators/src/errors.ts (1)

3-20: LGTM!

packages/decorators/src/__tests__/decorators.test.ts (1)

15-127: LGTM!

Also applies to: 169-179

packages/decorators/package.json (2)

1-20: LGTM!

Also applies to: 29-30


21-28: 🩺 Stability & Availability

Keep @sverka/core in devDependencies. Only the test suite imports it; production source does not reference it.

			> Likely an incorrect or invalid review comment.
packages/decorators/src/index.ts (1)

1-6: LGTM!

packages/decorators/src/registry.ts (1)

1-4: LGTM!

packages/decorators/src/__tests__/public-api.test.ts (1)

1-35: LGTM!

packages/decorators/tsconfig.json (1)

1-8: LGTM!

Comment thread packages/decorators/src/__tests__/decorators.test.ts Outdated
Comment thread packages/decorators/src/__tests__/public-api.test.ts Outdated
Comment thread packages/decorators/src/decorators.ts Outdated
Comment thread packages/decorators/src/decorators.ts
Comment thread packages/decorators/src/decorators.ts
Comment thread packages/decorators/src/decorators.ts
Comment thread packages/decorators/src/synthesize.ts
Comment thread packages/decorators/src/synthesize.ts
Comment thread packages/decorators/src/synthesize.ts Outdated
Comment thread specs/04-authoring-decorators/spec.md Outdated
@qodo-code-review

qodo-code-review Bot commented Aug 13, 2026 •

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (1) 📜 Skill insights (0)

Grey Divider


Action required

1. Options ignored for StepBuilder ✓ Resolved 🐞 Bug ≡ Correctness
Description
When a @step field is initialized with an SDK StepBuilder (from sh\...\`), decoratePipeline`
calls builder.build(...) and ignores decorator options (timeout, runtime, dependsOn,
outputs), so @stepWithOptions has no effect for builder-based steps.
Code

packages/decorators/src/synthesize.ts[R105-107]

+    const builder = value as StepBuilder;
+    builder.build(pipeline, name);
+    return;
Relevance

●●● Strong

Decorator options being ignored is a clear correctness gap; likely to apply options for builder
steps too.

PR-#34

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The synthesize logic applies options only for string-based steps; for builder-based steps it calls
build() directly. StepOptions includes fields like timeout/runtime, and StepBuilder
supports configuring those before build() constructs a ShellStep.

packages/decorators/src/synthesize.ts[83-108]
packages/decorators/src/types.ts[5-10]
packages/sdk/src/sh.ts[7-14]
packages/sdk/src/sh.ts[43-55]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
For `StepBuilder` step values, decorator-provided options are currently dropped. This makes `@stepWithOptions({ timeout: ... })` (and the documented `@step({ ... })`) silently ineffective for `sh`-authored steps.

### Issue Context
`StepBuilder` already exposes fluent setters (`timeout`, `runtime`, `dependsOn`, `outputs`) and `build()` ultimately creates the `ShellStep`. The decorator should merge/apply options before building.

### Fix Focus Areas
- packages/decorators/src/synthesize.ts[83-108]
- packages/decorators/src/types.ts[5-10]

### What to change
- In the `StepBuilder` branch, apply `options` by chaining on the builder before calling `build()`, e.g.:
 - `let b = builder; if (options?.timeout) b = b.timeout(options.timeout); ...; b.build(...)`
- Define precedence rules (document and implement), e.g.:
 - decorator options override builder settings, or
 - decorator options act as defaults only when builder has not set them.
- Add a test covering `@stepWithOptions` + `sh` builder to ensure `timeout`/`dependsOn` are applied.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. @step(options) crashes ✓ Resolved 🐞 Bug ≡ Correctness
Description
The code and spec claim @step(options) is supported, but step is only implemented as a bare
decorator (value, context) => void; using it as a factory via @step({timeout: ...}) will call it
with no context and crash at class definition time.
Code

packages/decorators/src/decorators.ts[R60-63]

+  context: ClassFieldDecoratorContext,
+): void {
+  registerFieldOnMetadata(context.metadata ?? {}, String(context.name), "step");
+}
Relevance

●●● Strong

Spec/code mismatch causing decorator crash is a clear correctness bug; likely to be fixed.

PR-#34

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The spec explicitly shows @step({ timeout: ... }), but the exported step function has the
standard decorator signature and always expects a context parameter; it does not return a
decorator function when called with options.

packages/decorators/src/decorators.ts[43-63]
specs/04-authoring-decorators/spec.md[38-50]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`step` is documented as supporting both `@step` and `@step(options)`, but the exported implementation only supports `@step` (bare). Using `@step({ ... })` will invoke `step(options)` with no `context` argument and then dereference `context.metadata`, causing a runtime error.

### Issue Context
The spec example uses `@step({ timeout: 600000 })` for a builder step.

### Fix Focus Areas
- packages/decorators/src/decorators.ts[43-76]
- specs/04-authoring-decorators/spec.md[38-52]

### What to change
- Implement an overload/dispatch for `step`:
 - If called with 1 argument (options), validate and return a decorator function (delegate to `stepWithOptions`).
 - If called with 2 arguments (value, context), treat as bare decorator.
- Ensure the public docs/spec either:
 - continue to support `@step(options)` (preferred since spec already shows it), or
 - explicitly remove/replace it everywhere with `@stepWithOptions(...)`.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


3. Decorator metadata may be undefined ✓ Resolved 🐞 Bug ☼ Reliability
Description
The decorators assume context.metadata is always a shared object, but it can be undefined when
Symbol.metadata isn’t available; @pipeline stores context.metadata! anyway, and other
decorators fall back to fresh {} objects, losing registrations and causing decoratePipeline to
throw NOT_A_PIPELINE or synthesize an empty pipeline.
Code

packages/decorators/src/decorators.ts[R23-25]

+): This {
+  (target as unknown as Record<symbol, object>)[PIPELINE_SYMBOL] = context.metadata!;
+  return target;
Relevance

●●● Strong

Likely fix: avoid undefined metadata and lost registrations; team tends to harden error-prone paths.

PR-#34
PR-#32

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
@pipeline stores context.metadata! without ensuring it’s defined, while field decorators use
context.metadata ?? {} which can be a new object per decorator invocation. TypeScript documents
that Symbol.metadata needs a polyfill and its decorator lib types explicitly allow metadata to
be undefined when Symbol.metadata is absent.

packages/decorators/src/decorators.ts[20-26]
packages/decorators/src/decorators.ts[58-63]
🌐 TypeScript 5.2 release notes state decorator metadata can be accessed via context.metadata/Symbol.metadata, and that a runtime polyfill for Symbol.metadata is needed because most runtimes don’t support it natively.
🌐 TypeScript’s lib/decorators.d.ts defines metadata as DecoratorMetadataObject | undefined when globalThis.Symbol.metadata is not present, meaning context.metadata is not guaranteed to be defined.

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`context.metadata` is typed/allowed to be `undefined` when the runtime doesn't provide `Symbol.metadata`. Current code writes `context.metadata!` onto the class and registers fields into `context.metadata ?? {}`, which can result in storing `undefined` for pipelines and/or registering into throwaway objects.

### Issue Context
TypeScript’s decorator metadata requires a runtime `Symbol.metadata` polyfill to guarantee `context.metadata` is present. Without it, this package’s core API can fail at class definition time or during `decoratePipeline`.

### Fix Focus Areas
- packages/decorators/src/decorators.ts[20-26]
- packages/decorators/src/decorators.ts[58-99]

### What to change
- Stop depending on `context.metadata` being defined.
- Implement an explicit, shared per-class metadata store:
 - Use `context.addInitializer(...)` in field/method decorators to attach metadata onto the class constructor (e.g., `this.constructor[PIPELINE_SYMBOL] ??= {}`) and register the field there.
 - In `@pipeline`, ensure the constructor is marked as a pipeline and ensure the same metadata object exists.
- Alternatively (if you prefer), add/document a required `Symbol.metadata` polyfill and fail fast with a clear error if it’s missing (but don’t silently fall back to `{}` per-decorator).

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


View high (1)
4. Method steps unsupported ✓ Resolved 🐞 Bug ≡ Correctness
Description
The spec claims @step can be used as a planning method, but decoratePipeline never handles
function values: prototype methods read as function and fall through to INVALID_FIELD, and the
current “method” branch is unreachable because it only runs when the step value is undefined.
Code

packages/decorators/src/synthesize.ts[R142-145]

+  throw new DecoratorError(
+    `step field '${name}' has invalid value type: ${typeof value}`,
+    "INVALID_FIELD",
+  );
Relevance

●●● Strong

Contract break vs spec for method steps is a correctness bug; likely to adjust handling for function
values.

PR-#34

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The synthesis code only treats method steps as value === undefined, but real methods are
functions. The spec simultaneously documents method-step support, making the current behavior a
contract break.

packages/decorators/src/synthesize.ts[89-146]
specs/04-authoring-decorators/spec.md[99-105]
specs/04-authoring-decorators/spec.md[140-144]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
The implementation advertises method-based steps, but the synthesis logic rejects function-valued steps and the method-handling block is gated by `value === undefined`, which does not match how methods appear on instances.

### Issue Context
Spec 04 describes method-based steps and includes them in the test plan.

### Fix Focus Areas
- packages/decorators/src/synthesize.ts[89-146]
- specs/04-authoring-decorators/spec.md[99-105]

### What to change
Choose one:
1) **Implement method steps end-to-end**
  - Update the decorator(s) to support method decorators (use `ClassMethodDecoratorContext` or a union with `ClassFieldDecoratorContext`).
  - Record method steps distinctly in metadata.
  - In `decoratePipeline`, handle `typeof value === "function"` (or use recorded kind) and execute planning with a well-defined API (and tests).
2) **Remove method-step claims**
  - Delete the unreachable method-step code path.
  - Remove method-step examples and test-plan items from the spec until implemented.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

5. Method-step logic untested ✓ Resolved 📘 Rule violation ▣ Testability
Description
createStepFromField() implements method-based steps (planning context and
MISSING_INITIALIZER/INVALID_FIELD errors), but the added tests cover only field-initializer
forms and the NOT_A_PIPELINE error. Untested branches increase risk of regressions in the new
decorator authoring surface.
Code

packages/decorators/src/synthesize.ts[R110-113]

+  if (value === undefined) {
+    // Could be a method-based step — check if the method exists.
+    const method = (instance as Record<string, unknown>)[name];
+    if (typeof method === "function") {
Relevance

●●● Strong

Repo has precedent accepting requests to add tests for non-trivial logic/branches.

PR-#29

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
PR Compliance ID 2649776 requires tests for non-trivial implementation changes. The PR adds
method-based step execution and related error paths in synthesize.ts, but the tests added cover
string shorthand, options, StepBuilder, entry/input behavior, conformance, and only the
NOT_A_PIPELINE error—leaving method-step planning and missing-initializer errors untested.

Rule 2649776: Require tests for all non-trivial implementation code changes
packages/decorators/src/synthesize.ts[110-146]
packages/decorators/src/tests/decorators.test.ts[15-179]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
New non-trivial behavior in `decoratePipeline` (method-based `@step` planning + error branches like `MISSING_INITIALIZER`) is not exercised by automated tests.

## Issue Context
Compliance requires tests for all non-trivial implementation changes. `createStepFromField()` contains logic for method-based steps via a planning context (`createPlanningContext`) and specific error cases that currently have no direct test coverage.

## Fix Focus Areas
- packages/decorators/src/synthesize.ts[110-146]
- packages/decorators/src/__tests__/decorators.test.ts[15-179]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


6. Invalid @input silently dropped ✓ Resolved 🐞 Bug ☼ Reliability
Description
decoratePipeline silently ignores @input fields whose initializer isn’t an object with a type
property, which can leave pipelines missing declared inputs with no error and very confusing
downstream behavior.
Code

packages/decorators/src/synthesize.ts[R41-44]

+    if (meta.kind === "input") {
+      const value = (instance as Record<string, unknown>)[name];
+      if (value !== undefined && typeof value === "object" && value !== null && "type" in value) {
+        inputs[name] = value as Input;
Relevance

●●● Strong

Team has accepted changes to avoid silent failures; likely will add error/warning for invalid
@input.

PR-#32
PR-#34

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The input collection loop only registers inputs when a minimal shape check passes; there is no
else branch to raise an error for invalid/missing initializers, so decorated inputs can be
silently excluded from PipelineProps.inputs.

packages/decorators/src/synthesize.ts[38-53]
specs/04-authoring-decorators/spec.md[110-113]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
An `@input` decorator signals that a field is intended to become a pipeline input, but the current implementation only adds it if a loose shape-check passes and otherwise drops it silently.

### Issue Context
The spec says an `@input` initializer is an `Input` object; silent omission makes typos/missing initializers hard to debug.

### Fix Focus Areas
- packages/decorators/src/synthesize.ts[38-47]
- specs/04-authoring-decorators/spec.md[110-113]

### What to change
- If a field is decorated with `@input`:
 - Throw `DecoratorError("INVALID_FIELD")` (or a dedicated code) when the initializer is missing or not a valid `Input` shape, instead of silently skipping.
 - Optionally perform stronger validation than just `'type' in value` (e.g., ensure `type` is an expected string literal).
- Add a test that `@input` with an invalid initializer throws a `DecoratorError`.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


7. Spec file not numbered 📘 Rule violation ⚙ Maintainability
Description
The modified specification document is specs/04-authoring-decorators/spec.md, but the file name
spec.md does not start with a numeric identifier as required. This breaks the repository’s spec
naming convention and makes specs harder to track and reference consistently.
Code

specs/04-authoring-decorators/spec.md[R3-5]

+**Status:** Active
+**Source:** specs/architecture-spec.md §9.3–9.8, §12, §14, §15
+**Package:** `@sverka/decorators` (new)
Relevance

●● Moderate

No clear repo precedent on spec filename numbering beyond directory; rule may be interpreted as
satisfied already.

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
PR Compliance ID 2663931 requires specification documents introduced or modified to be placed under
specs/ and have filenames that begin with a numeric identifier. This PR modifies
specs/04-authoring-decorators/spec.md, where the filename spec.md does not include the required
numeric prefix.

Rule 2663931: Place and number specification documents under specs/
specs/04-authoring-decorators/spec.md[1-5]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
A specification document modified in this PR does not follow the required numbering convention for spec filenames.

## Issue Context
The checklist requires that each specification document introduced or modified lives under `specs/` *and* that the spec file name begins with a numeric identifier (e.g., `001_...`, `002-...`). This PR updates `specs/04-authoring-decorators/spec.md`, whose filename `spec.md` does not include the numeric prefix.

## Fix Focus Areas
- specs/04-authoring-decorators/spec.md[1-5]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Context
✅ Compliance rules (platform): 8 rules
✅ Web pages:
  +4 more
Review mode: ⚖️ Balanced: Downgraded extended -> standard: change is below the extended eligibility bar (hunks 13/18, lines 845/200; both must reach the floor). Router rationale: This is a new decorator authoring surface with substantial metadata, synthesis, runtime evaluation, and API logic across many independent paths, creating a dense set of easy-to-miss behavioral defects.

Grey Divider

Tip of the day
💡 Did you know, you can type 'qodo, fix this' on a finding and the fix lands right on your PR

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Qodo Logo

Comment thread packages/decorators/src/synthesize.ts Outdated
Comment thread specs/04-authoring-decorators/spec.md
Comment thread packages/decorators/src/decorators.ts
Comment thread packages/decorators/src/decorators.ts Outdated
Comment thread packages/decorators/src/synthesize.ts Outdated
Comment thread packages/decorators/src/synthesize.ts
Comment thread packages/decorators/src/synthesize.ts Outdated
@codeant-ai codeant-ai Bot added size:XL This PR changes 500-999 lines, ignoring generated files and removed size:XL This PR changes 500-999 lines, ignoring generated files labels Aug 13, 2026
@codeant-ai codeant-ai Bot added size:XL This PR changes 500-999 lines, ignoring generated files and removed size:XL This PR changes 500-999 lines, ignoring generated files labels Aug 13, 2026
ThePlenkov added a commit that referenced this pull request Aug 13, 2026
Co-Authored-By: Petr Plenkov <petr.plenkov@gmail.com>
ThePlenkov added a commit that referenced this pull request Aug 13, 2026
Co-Authored-By: Petr Plenkov <petr.plenkov@gmail.com>
@nx-cloud

nx-cloud Bot commented Aug 13, 2026 •

Copy link
Copy Markdown

View your CI Pipeline Execution ↗ for commit ab2ea85

Command Status Duration Result
nx affected -t lint test ✅ Succeeded 1s View ↗
nx affected -t build ✅ Succeeded 17s View ↗

💡 Verify your cache is correct by running tasks in a sandbox. Read docs ↗


☁️ Nx Cloud last updated this comment at 2026-08-13 21:40:30 UTC

ThePlenkov added a commit that referenced this pull request Aug 13, 2026
Co-Authored-By: Petr Plenkov <petr.plenkov@gmail.com>
@coderabbitai coderabbitai Bot mentioned this pull request Aug 13, 2026
6 tasks
@sonarqubecloud

Copy link
Copy Markdown

ThePlenkov and others added 6 commits August 13, 2026 23:36
New @sverka/decorators package — the third authoring surface. Uses TC39
standard decorators (TypeScript 5.0+, no experimentalDecorators).

Decorators:
- @pipeline: class decorator marking a Sverka pipeline
- @step: field decorator for string shorthand or StepBuilder
- @stepWithOptions(options): factory form for step with runtime/timeout/outputs
- @entry(trigger): field decorator for entry definitions
- @input: field decorator for pipeline inputs
- @output: field decorator for pipeline outputs

decoratePipeline(PipelineClass, project, id) creates a Pipeline construct
from a decorated class, producing the same Definition Graph as the Construct
and SDK APIs.

Metadata is stored via context.metadata (TC39 per-class metadata object),
retrieved from the class constructor via a Symbol property (Symbol.metadata
is not yet widely implemented in Bun).

11 decorator tests (8 behavior + 3 public API). 102 tests across 4 packages.
No any types. override readonly cause present.

Specs: 04-authoring-decorators (§9.3–9.8, §12, §14, §15).

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
…ethod-step support

Co-Authored-By: Petr Plenkov <petr.plenkov@gmail.com>
Co-Authored-By: Petr Plenkov <petr.plenkov@gmail.com>
Co-Authored-By: Petr Plenkov <petr.plenkov@gmail.com>
Split validateStepOptions (complexity 14→4) into per-field validators
and validateInput (complexity 13→4) into typed helper functions.

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
- S1848: Add void operator to CDK construct instantiations (BUG, MAJOR)
- S3776: Extract createStepFromMethod to reduce cognitive complexity (CRITICAL)
- S4623: Remove redundant undefined argument (MAJOR)
- S1128: Remove unused PlanningContext import (MINOR)
- S2699: Add assertions to compile-time type test (BLOCKER)
- S5914: Replace always-succeeding assertions with real checks (MAJOR)

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
@sonarqubecloud

Copy link
Copy Markdown

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

baz: needs review size:XXL This PR changes 1000+ lines, ignoring generated files

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant