Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
a8cef7f
Bump version -> `2.0.0-SNAPSHOT.416`
alexander-yevsyukov May 5, 2026
5c5d60c
Bump Validation -> `2.0.0-SNAPSHOT.415`
alexander-yevsyukov May 5, 2026
46d1004
Bump Validation in docs
alexander-yevsyukov May 5, 2026
7ab7dc3
Update `_examples` ref.
alexander-yevsyukov May 5, 2026
2dba107
Bump Gradle -> `9.5.0`
alexander-yevsyukov May 5, 2026
391adf5
Update dependency reports
alexander-yevsyukov May 5, 2026
fd36d85
Update (c) header
alexander-yevsyukov May 5, 2026
ace531d
Remove duplicated references to `spine/options.proto`
alexander-yevsyukov May 5, 2026
019208b
Strip the outdated content from `README.md`
alexander-yevsyukov May 5, 2026
c09686d
Add "Why" and "How it works" sections to the overview documentation
alexander-yevsyukov May 5, 2026
bdc978a
Improve root section name
alexander-yevsyukov May 5, 2026
131ef01
Improve readability of the "Key modules" section
alexander-yevsyukov May 5, 2026
7bc1a23
Update Developer's guide section number
alexander-yevsyukov May 5, 2026
f7768f7
Add plan for writing Developer's guie
alexander-yevsyukov May 5, 2026
5ca5f7c
Draft the Architecture section
alexander-yevsyukov May 5, 2026
301986f
Update `embed-code-go` binaries
alexander-yevsyukov May 5, 2026
462705b
Add more code roots for `embed-code`
alexander-yevsyukov May 5, 2026
8a24808
Use `embed-code` for samples
alexander-yevsyukov May 5, 2026
974b8a6
Add overview section and page placeholders
alexander-yevsyukov May 5, 2026
68d5290
Improve margins on the architecture diagram
alexander-yevsyukov May 5, 2026
43cba27
Update sequence of sections in the plan
alexander-yevsyukov May 5, 2026
6d7d1d9
Add missing comma
alexander-yevsyukov May 5, 2026
45cf382
Add Validation model section
alexander-yevsyukov May 5, 2026
11e3854
Remove "(deep dive)" suffix
alexander-yevsyukov May 5, 2026
c35fde5
Use sentence capitalization
alexander-yevsyukov May 5, 2026
fafc056
Use typography quotes around a link in the text
alexander-yevsyukov May 5, 2026
3cffd56
Avoid module names in titles
alexander-yevsyukov May 5, 2026
3738b41
Fix the delivery path in Mermaid diagram
alexander-yevsyukov May 5, 2026
92425c4
Avoid referencing "AST node" in docs
alexander-yevsyukov May 6, 2026
be26044
Improve table format in Markdown
alexander-yevsyukov May 6, 2026
fb9c9f7
Add Java code generation section
alexander-yevsyukov May 6, 2026
c3a5853
Improve wording of Java codegen docs
alexander-yevsyukov May 6, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
142 changes: 142 additions & 0 deletions .agents/tasks/plan-writing-developers-guide.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
# Writing Developer's Guide Plan

This plan outlines the steps required to write a comprehensive Developer's Guide
for the Spine Validation project.

## Audience and scope

The Developer's Guide is for contributors to the Validation library itself, and for
readers who want a deep understanding of how the library works internally. It is
distinct from the User's Guide (under `docs/content/docs/validation/00-intro` …
`05-custom-validation`), which targets consumers of the library.

The guide lives under `docs/content/docs/validation/06-developers-guide/`.

## Sections

### 1. Overview and audience

Explains who this guide is for, how it complements the User's Guide, and the
high-level mental model (compile-time codegen + runtime checks). Sets expectations
about prerequisite knowledge (Protobuf, Gradle, Spine Compiler).

### 2. Architecture

Replaces the previously deleted `architecture.md` with an up-to-date description:

- The compile-time vs. runtime split.
- How `:context` (language-agnostic validation model), `:java` (Java codegen via
Spine Compiler plugin), and `:jvm-runtime` (runtime APIs and error types)
collaborate.
- The role of `:java-bundle` and `:gradle-plugin` in distribution.
- A diagram showing the flow: `.proto` + options → `:context` model → `:java`
generator → generated validation code → `:jvm-runtime` APIs at execution time.

### 3. Key modules

Already drafted in `key-modules.md`. Keep current; add cross-links from sections 2
and 4–8 as those sections are written.

### 4. The validation model in `:context`

Deep dive into the language-agnostic model:

- Views, events, and reactions; how built-in options are translated into model
state.
- How custom options plug in via the `ValidationOption` SPI from the model side.
- Error reporting conventions inside the model.

### 5. Java code generation in `:java`

How the Spine Compiler plugin in `:java` produces validation code:

- Plugin entry points and lifecycle.
- How the model from `:context` drives generation.
- `ValidationOption` SPI from the codegen side: how a custom option contributes
generated code.
- Conventions for the shape of generated validators.

### 6. Runtime library `:jvm-runtime`

What ships in `:jvm-runtime` and how generated code uses it:

- `MessageValidator`, validation/constraint APIs, `ValidationException`.
- Error Protobuf types and how violations are surfaced.
- Extension hooks available at runtime, including `@Validator`.

### 7. Extension points (deep dive)

Internals behind the public extension surface, complementing the User's Guide
`04-validators/` and `05-custom-validation/`:

- `@Validator` and the validator registry: discovery, ordering, lifecycle.
- `ValidationOption` SPI end-to-end (cross-references sections 4 and 5).
- Constraints on what extensions can and cannot do, and why.

### 8. Adding a new built-in validation option

Contributor-side counterpart to the User's Guide `05-custom-validation/` section.
Where the User's Guide explains how a *consumer* adds a custom option to their
own project, this section explains how a *contributor* adds a new **standard**
option to the Validation library. Outline:

- Declaring the option in `spine/options.proto` in the `base-libraries` repo
(link to that repo and to `options.proto`); versioning/coordination notes.
- Modeling the option in `:context`: the corresponding view, events, and
reactions.
- Implementing code generation in `:java`.
- Adding runtime support in `:jvm-runtime` if the option needs new runtime
helpers or error types.
- Writing tests across `:context-tests`, `:tests:vanilla`, and any specialized
`:tests:*` modules.
- Documenting the new option in the User's Guide `03-built-in-options/`.

### 9. Testing strategy

Map of the test modules and when to add to which:

- `:context-tests` — Prototap-based compilation tests for the model.
- `:tests:vanilla` — baseline integration without custom extensions.
- `:tests:extensions`, `:tests:consumer`, `:tests:consumer-dependency` — custom
options and consumer-side scenarios.
- `:tests:validator`, `:tests:validator-dependency` — `@Validator` scenarios.
- `:tests:runtime`, `:tests:validating` — runtime behavior and shared fixtures.
- Guidance on choosing the right module for a new test.

### 10. Build, packaging, and release

How the multi-project build is wired and how artifacts are produced:

- Gradle multi-project layout; relationship between `:java`, `:java-bundle`, and
`:gradle-plugin`.
- Why `:java-bundle` exists (fat JAR for compiler plugin distribution).
- Version flow and how the Gradle plugin is consumed by downstream projects.

## Conventions

- **Depth of code walkthroughs**: sections 5–7 use short snippets paired with
links to the source code. No long inline listings — the source is the source
of truth.
- **Diagrams**: section 2 (and any later section that benefits) uses Mermaid.
Pick the Mermaid diagram type that best fits the content (flowchart, sequence,
class, etc.).

## Out of scope

- A reference for standard validation options. The User's Guide
`03-built-in-options/` already covers this; the Developer's Guide instead
teaches contributors how to add new standard options (section 4).
- Contributing workflow / coding standards. These remain in `CONTRIBUTING.md`
and the `.agents` directory; the Developer's Guide does not duplicate them.

## Execution order

1. Section 2 (Architecture) — anchors everything else.
2. Section 1 (Overview) — short, written after section 2 so framing is accurate.
3. Sections 4, 5, 6 — internals, in dependency order.
4. Section 7 — builds on 4–6.
5. Section 8 — the "adding a new built-in option" walkthrough, which exercises
sections 2 and 4–7.
6. Sections 9 and 10 — testing and build/release.
7. Update `_index.md` and `docs/data/docs/validation/2-0-0-snapshot/sidenav.yml`
as each section lands.
87 changes: 9 additions & 78 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,6 @@ Spine Validation solves this by modifying the code generated by the Protobuf com
At build time, Spine Validation injects assertions directly into the generated Java classes,
enabling automatic enforcement of constraints without explicit API calls in application code.

## Table of Contents

- [Prerequisites](#prerequisites)
- [Validation in Action](#validation-in-action)
- [Architecture](#architecture)
- [Extending the Library](#extending-the-library)

## Prerequisites

This library is built with Java 17.
Expand Down Expand Up @@ -78,12 +71,12 @@ optionalError.ifPresent(err -> {
});
```

### Validation Options
## Validation Options

Validation options are defined by the following files:

1. [options.proto](https://github.com/SpineEventEngine/base-libraries/blob/master/base/src/main/proto/spine/options.proto).
2. [time_options.proto](https://github.com/SpineEventEngine/time/blob/master/time/src/main/proto/spine/time_options.proto).
1. [`options.proto`][options-proto]
2. [`time_options.proto`][time-options-proto]

Users must import these .proto files to use the options they define.

Expand All @@ -92,81 +85,19 @@ import "spine/options.proto"; // Brings all options, except for time-related one
import "spine/time_options.proto"; // Brings time-related options.
```

# Adding custom validation
## Adding custom validation

Users can extend the library by providing custom Protobuf options and code generation logic.

Follow these steps to create a custom option:

1. Declare a Protobuf [extension](https://protobuf.dev/programming-guides/proto3/#customoptions)
in your `.proto` file.
2. Register it via `io.spine.option.OptionsProvider`.
3. Implement the following entities:
- Policy (`MyOptionPolicy`) – discovers and validates the option.
- View (`MyOptionView`) – accumulates valid option applications.
- Generator (`MyOptionGenerator`) – generates Java code for the option.
4. Register them via `io.spine.tools.validation.java.ValidationOption`.

Below is a workflow diagram for a typical option:

![Typical custom option](.github/readme/typical_custom_option.jpg)

Take a look at the `:java-tests:extensions` module that contains a full example of
implementation of the custom `(currency)` option.

Note that a custom option can provide several policies and views, but only one generator.
This allows building more complex models, using more entities and events.

Let's take a closer look at each entity.

### Policy

Usually, this is an entry point to the option handling.

The policy subscribes to one of `*OptionDiscovered` events:

- `FileOptionDiscovered`.
- `MessageOptionDiscovered`.
- `FieldOptionDiscovered`.
- `OneofOptionDiscovered`.

It filters incoming events, taking only those who contain the option of the interest. The policy
may validate the option application, query `TypeSystem`, extract and transform data arrived with
the option, if any. Once ready, it emits an event signaling that the discovered option is valid
and ready for the code generation.

The policy may report a compilation warning or an error, failing the whole compilation if it
finds an illegal application of the option.

For example:

1. An unsupported field type.
2. Illegal option content (invalid regex, parameter, signature).

The policy may just ignore the discovered option and emit `NoReaction`. A typical example
of this is a boolean option, such as `(required)`, which does nothing when it is set to `false`.

The desired behavior depends on the option itself.

### View

Views accumulate events from policies, serving as data providers for the validation model
used by code generators. Views are typically simple and only accumulate data; for more complex
logic, use policies.

Usually, one view represents a single application of an option.

### Generator

The generator is an entity that provides an actual implementation of the option behavior.
The generator produces Java code for every application of that option within the message type.

It has access to the `Querying` interface and can query views to find those belonging
to the processed message type.
See the [Custom validation](docs/content/docs/validation/05-custom-validation/) section
of the User Guide for details.

[codecov]: https://codecov.io/gh/SpineEventEngine/validation
[codecov-badge]: https://codecov.io/gh/SpineEventEngine/validation/branch/master/graph/badge.svg
[license-badge]: https://img.shields.io/badge/license-Apache%20License%202.0-blue.svg?style=flat
[license]: http://www.apache.org/licenses/LICENSE-2.0
[gh-actions]: https://github.com/SpineEventEngine/validation/actions
[ubuntu-build-badge]: https://github.com/SpineEventEngine/validation/actions/workflows/build-on-ubuntu.yml/badge.svg

[options-proto]: https://github.com/SpineEventEngine/base-libraries/blob/master/base/src/main/proto/spine/options.proto
[time-options-proto]: https://github.com/SpineEventEngine/time/blob/master/time/src/main/proto/spine/time_options.proto
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ object Validation {
/**
* The version of the Validation library artifacts.
*/
const val version = "2.0.0-SNAPSHOT.414"
const val version = "2.0.0-SNAPSHOT.415"

/**
* The last version of Validation compatible with ProtoData.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ package io.spine.tools.validation
* We have the same items in this enum as in `io.spine.validation.RuntimeErrorPlaceholder`
* in the runtime library, which is exactly as this one. Please keep them in sync.
* This duplication is done intentionally to prevent clash between the runtime library,
* which is added to the classpath of the Compiler and the runtime library, which is part
* which is added to the classpath of the Compiler, and the runtime library, which is part
* of the Compiler itself because it is a part of Spine. As we complete our migration
* of validation to codegen, the runtime library will either be significantly simplified,
* or even its content may be moved to `base`. Then, the duplicate enum should be removed.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,4 +105,4 @@ public abstract class ValidationPlugin(
IfSetAgainReaction(),
RequireReaction()
)
)
) // Plugin
Loading
Loading