[
https://issues.apache.org/jira/browse/GROOVY-12468?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=18128996#comment-18128996
]
ASF GitHub Bot commented on GROOVY-12468:
-----------------------------------------
codecov-commenter commented on PR #2992:
URL: https://github.com/apache/groovy/pull/2992#issuecomment-6285612189
##
[Codecov](https://app.codecov.io/gh/apache/groovy/pull/2992?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache)
Report
:x: Patch coverage is `82.81250%` with `11 lines` in your changes missing
coverage. Please review.
:white_check_mark: Project coverage is 72.4360%. Comparing base
([`c227066`](https://app.codecov.io/gh/apache/groovy/commit/c227066191b1a0c95b12c3672cc5f333fc4f27d7?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache))
to head
([`21fe917`](https://app.codecov.io/gh/apache/groovy/commit/21fe917740578fe26386293b840061cc034c0e31?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache)).
:warning: Report is 4 commits behind head on master.
| [Files with missing
lines](https://app.codecov.io/gh/apache/groovy/pull/2992?dropdown=coverage&src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache)
| Patch % | Lines |
|---|---|---|
|
[...he/groovy/contracts/ast/SpecASTTransformation.java](https://app.codecov.io/gh/apache/groovy/pull/2992?src=pr&el=tree&filepath=subprojects%2Fgroovy-contracts%2Fsrc%2Fmain%2Fjava%2Forg%2Fapache%2Fgroovy%2Fcontracts%2Fast%2FSpecASTTransformation.java&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache#diff-c3VicHJvamVjdHMvZ3Jvb3Z5LWNvbnRyYWN0cy9zcmMvbWFpbi9qYXZhL29yZy9hcGFjaGUvZ3Jvb3Z5L2NvbnRyYWN0cy9hc3QvU3BlY0FTVFRyYW5zZm9ybWF0aW9uLmphdmE=)
| 82.8125% | [2 Missing and 9 partials :warning:
](https://app.codecov.io/gh/apache/groovy/pull/2992?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache)
|
<details><summary>Additional details and impacted files</summary>
[](https://app.codecov.io/gh/apache/groovy/pull/2992?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache)
```diff
@@ Coverage Diff @@
## master #2992 +/- ##
==================================================
+ Coverage 72.4271% 72.4360% +0.0089%
- Complexity 40610 40633 +23
==================================================
Files 1643 1644 +1
Lines 142669 142733 +64
Branches 26793 26812 +19
==================================================
+ Hits 103331 103390 +59
+ Misses 29832 29830 -2
- Partials 9506 9513 +7
```
| [Files with missing
lines](https://app.codecov.io/gh/apache/groovy/pull/2992?dropdown=coverage&src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache)
| Coverage Δ | |
|---|---|---|
|
[...he/groovy/contracts/ast/SpecASTTransformation.java](https://app.codecov.io/gh/apache/groovy/pull/2992?src=pr&el=tree&filepath=subprojects%2Fgroovy-contracts%2Fsrc%2Fmain%2Fjava%2Forg%2Fapache%2Fgroovy%2Fcontracts%2Fast%2FSpecASTTransformation.java&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache#diff-c3VicHJvamVjdHMvZ3Jvb3Z5LWNvbnRyYWN0cy9zcmMvbWFpbi9qYXZhL29yZy9hcGFjaGUvZ3Jvb3Z5L2NvbnRyYWN0cy9hc3QvU3BlY0FTVFRyYW5zZm9ybWF0aW9uLmphdmE=)
| `82.8125% <82.8125%> (ø)` | |
... and [9 files with indirect coverage
changes](https://app.codecov.io/gh/apache/groovy/pull/2992/indirect-changes?src=pr&el=tree-more&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache)
</details>
<details><summary> :rocket: New features to boost your workflow: </summary>
- :snowflake: [Test
Analytics](https://docs.codecov.com/docs/test-analytics): Detect flaky tests,
report on failures, and find test suite problems.
- :package: [JS Bundle
Analysis](https://docs.codecov.com/docs/javascript-bundle-analysis): Save
yourself from yourself by tracking and limiting bundle sizes in JS merges.
</details>
> @Spec spike
> -----------
>
> Key: GROOVY-12468
> URL: https://issues.apache.org/jira/browse/GROOVY-12468
> Project: Groovy
> Issue Type: Bug
> Reporter: Paul King
> Assignee: Paul King
> Priority: Major
>
> _This is a spike of a feature several other languages are experimenting
> with/supporting. It is essentially an annotation that records a comment (not
> unlike @Groovydoc) but can have special meaning for tooling - allowing
> "hole-driven" development._
> h2. Summary
> Add a {{@Spec}} annotation that marks a method (and optionally a loop or
> local declaration) as having a prose specification intended as an LLM prompt,
> alongside the method's typed signature and any {{@Requires}}/{{@Ensures}}
> contracts. A method carrying {{@Spec}} with an empty body is an unfilled
> "hole". A tool (outside the compiler) fills the hole ahead of time by writing
> a generated body into the source under the spec, and the spec stays in place
> as documentation and as the input for later regeneration.
> The annotation is essentially a structured comment: unlike a plain comment,
> tools can find it, and the compiler can tell a filled body from an unfilled
> one.
> h2. Motivation
> Martin Odersky's Scala Days 2026 keynote showed program holes filled ahead of
> time: a method with a typed signature, a prose spec string and {{???}}, and a
> "sync" step where an agent writes the body under the spec. Groovy can offer
> the same workflow with a stronger guarantee, because a fill can be checked
> against contracts, not just against types.
> * The spec is written for both people and models, and it lives next to the
> code it describes.
> * Contracts make the spec checkable. For example, the keynote's own generated
> date parser accepts 31 February; a one-line {{@Ensures}} catches it.
> * No runtime evaluation, in-process compilation or typed binding is needed:
> the generated body sits in real source and the compiler sees its real scope.
> * Writing contracts for this example already found GROOVY-12463 (contracts
> skipped on a trailing implicit return after an early {{return}}).
> h2. Example
> {code:groovy}
> import groovy.contracts.Ensures
> import groovy.contracts.Requires
> class Dates {
> @Spec('''
> Parse an ISO-8601 calendar date (yyyy-MM-dd) into its year, month
> and day. Reject dates that do not exist, such as 2026-02-31.
> ''')
> @Requires({ text != null })
> @Ensures({ result.month in 1..12 && result.day <=
> YearMonth.of(result.year, result.month).lengthOfMonth() })
> static DateParts parse(String text) { } // unfilled: throws until synced
> }
> {code}
> After a sync, the body is filled in and the {{@Spec}} remains, with a
> {{fill}} member recording what was generated (see below).
> h2. Proposal
> h3. 1. The annotation
> * {{@Spec(String value)}}: the prose specification.
> * Target: methods; also {{@ExtendedTarget(ExtendedElementType.LOOP)}} and
> local variable declarations for smaller holes. Probes on 6.0.0 confirm the
> annotation can be placed on {{for}}, {{while}} and {{do-while}} loops and on
> local declarations.
> * {{fill}} member (optional, written by tooling): a hash of the spec text and
> of the generated body, so a tool can tell whether the spec or the body has
> changed since the last fill.
> * Source/class retention to be decided. Loop and local annotations are not
> written to the class file in any case, so those specs exist only in source.
> h3. 2. A small local transform
> * A method carrying {{@Spec}} with an empty body is compiled to throw (for
> example {{UnsupportedOperationException("unfilled @Spec: Dates.parse")}})
> instead of returning {{null}}. An unfilled loop can be made to throw
> similarly.
> * The transform never calls a model. Compiling still runs nothing beyond what
> it runs today.
> h3. 3. The sync tool (outside core)
> Not part of this ticket's compiler change, but it defines the contract the
> annotation must support. A library with a command line (and possibly an MCP
> tool) that IDE plugins and CI call rather than reimplement:
> * Find unfilled specs; prompt the model with the prose, contracts, signature
> and types in scope.
> * Compile each candidate with the configured type checkers, check contracts
> (by proof via groovy-verify where possible, otherwise by tests), and retry on
> diagnostics or counterexamples. Only a candidate that passes is written back.
> * Use the {{fill}} hash to classify each spec:
> ** *in sync*: nothing to do
> ** *stale*: spec changed, body untouched; regenerate
> ** *hand-edited*: body changed by a person; never overwrite. Offer to update
> the spec (as a diff for a person to approve, and only if the edited body
> still satisfies the contracts), drop {{@Spec}}, or report the drift
> ** *conflict*: both changed; a person resolves it
> ** *unfilled*: no body yet
> * Confirmation scales with how well a fill was checked: proved fills apply
> without asking; fills whose contracts or tests pass apply and are shown for
> review; compile-only fills ask; failures leave the hole unfilled with the
> last diagnostics. Updating a spec from code always asks.
> * A non-interactive mode for CI fails the build when any spec is stale,
> hand-edited or unfilled.
> h2. Open questions
> * *Home*: should the annotation and transform start in core
> ({{groovy.transform.Spec}}), in groovy-contracts next to
> {{@Requires}}/{{@Ensures}}, or outside the project until the convention has
> proved itself?
> * *Retention*: source only, or class retention so method-level specs are
> visible to reflection and to tools reading compiled libraries?
> * *Hash format*: what exactly goes into {{fill}}, and should
> whitespace/formatting changes to the body count as a hand edit?
> * *Static scope*: should a {{@Spec}} method be compiled statically by
> default, so checkers see every call in generated code? Probes on 6.0.0 show
> per-method static compilation works, including closures and anonymous inner
> classes in the method; a loop-level spec would require compiling the whole
> enclosing method statically.
> h2. Out of scope
> * Calling a model from the compiler or from an AST transform.
> * Runtime (LACUNA-style) holes filled while the program runs; those need a
> typed binding (GROOVY-12462) and a restricted compiler profile (GEP pending),
> and can build on this later.
--
This message was sent by Atlassian Jira
(v8.20.10#820010)