Skip to content
This repository was archived by the owner on Feb 4, 2026. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
9388607
chore: prepare release 0.6.0
siy Jan 27, 2026
804b245
chore: bump Aether to 0.8.1 and re-enable slice-processor-tests
siy Jan 27, 2026
1349326
fix: update slice init templates for 0.6.0
siy Jan 27, 2026
f25316f
fix: remove Sample prefix and use lowercased slice name for inner record
siy Jan 27, 2026
8982a50
docs: update version references to 0.6.0
siy Jan 27, 2026
8d037d2
fix: update regular project template Java version to 25
siy Jan 27, 2026
bf1248a
feat(init): use running binary version as minimum for jbct version re…
siy Jan 28, 2026
9e040e9
fix(init): correct slice template ValidationError and Promise API
siy Jan 28, 2026
8cccf2a
fix(init): add missing Cause import to slice template
siy Jan 28, 2026
35a3297
fix(init): implement message() method in ValidationError.EmptyValue
siy Jan 28, 2026
fdb4f5b
fix(init): use unwrap() instead of getOrThrow() in test template
siy Jan 28, 2026
03f9b14
feat(init): validate groupId and add annotation processor config to s…
siy Jan 28, 2026
1da48f8
docs: update changelog for 0.6.0 release
siy Jan 28, 2026
44f8135
docs(init): update README and tests for template changes
siy Jan 28, 2026
3533b34
docs(slice): update quickstart to reflect current template structure
siy Jan 28, 2026
57336a8
docs(slice): update README project structure
siy Jan 28, 2026
d743573
fix(slice): remove slice-api.properties for RFC-0004 compliance
siy Jan 28, 2026
6ff6316
style: format code after RFC-0004 changes
siy Jan 28, 2026
74c99ed
feat(slice): implement RFC-0007 infrastructure dependency handling
siy Jan 28, 2026
c7bd16a
fix(slice): correct property name for slice artifact ID
siy Jan 28, 2026
6a23aa4
fix(slice): fix dependency file generation and blueprint resolution
siy Jan 28, 2026
3b2603f
fix(slice): deduplicate local dependencies in blueprint
siy Jan 28, 2026
7fd74d5
feat(slice): include same-module slice dependencies in [slices] section
siy Jan 28, 2026
afdf429
fix(slice): resolve service file collision and add http-routing-adapt…
siy Jan 28, 2026
25ed24f
fix(slice): detect same-module dependencies by base package prefix
siy Jan 28, 2026
95fbf23
refactor(slice): move http-routing-adapter validation to maven plugin
siy Jan 28, 2026
c7e4576
fix(slice): generate infra dependency calls using factory methods
siy Jan 28, 2026
d0e40a3
fix(slice): transform factory bytecode to replace UNRESOLVED versions…
siy Jan 28, 2026
d831e34
chore: update changelog date to 2026-01-29
siy Jan 29, 2026
32e67aa
refactor: improve code quality in bytecode transformer and version re…
siy Jan 29, 2026
df31021
test: add unit tests for PackageSlicesMojo
siy Jan 29, 2026
084f664
refactor: use Result.all() with or() for version comparison
siy Jan 29, 2026
b052998
fix(slice): include Routes class and service file in slice JARs
siy Jan 31, 2026
bedcef8
feat(slice): remove unused blueprint properties, default to 3 instances
siy Jan 31, 2026
2f588c9
fix(slice): wrapper implements both Slice and slice interface
siy Jan 31, 2026
6421037
ci: fix cyclic dependency by installing modules individually
siy Jan 31, 2026
9f82c42
ci: install parent POM to fix dependency resolution
siy Jan 31, 2026
5d81abf
ci: exclude slice-processor (depends on unpublished Aether libs)
siy Jan 31, 2026
8b8edff
fix: address all PR review comments
siy Jan 31, 2026
6ba7e7b
refactor: fix JBCT compliance issues across codebase
siy Jan 31, 2026
0396e12
fix(slice): ensure deterministic route generation order
siy Jan 31, 2026
b6e6320
fix: address all JBCT compliance issues from parallel review
siy Jan 31, 2026
945d20b
refactor: rename SecurityError types to use past tense per JBCT
siy Feb 1, 2026
173acf8
fix: address all remaining JBCT compliance issues
siy Feb 1, 2026
72a7155
docs: document JBCT pattern exceptions for resource loading
siy Feb 1, 2026
be46bca
fix: address PR review comments for slice processing
siy Feb 1, 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
14 changes: 13 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,16 @@ jobs:
distribution: 'temurin'
cache: maven

- run: mvn verify -B -Djbct.skip -pl '!slice-processor-tests'
# Install modules individually to break cyclic dependency
- name: Install parent POM
run: mvn install -B -N -Djbct.skip=true

- name: Install jbct-core
run: mvn install -B -DskipTests -pl jbct-core -Djbct.skip=true

- name: Install jbct-maven-plugin
run: mvn install -B -DskipTests -pl jbct-maven-plugin -Djbct.skip=true

# Note: slice-processor modules excluded - they depend on unpublished Aether libraries
- name: Build and test core modules
run: mvn verify -B -pl jbct-core,jbct-cli -Djbct.skip=true
12 changes: 11 additions & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,18 @@ jobs:
distribution: 'temurin'
cache: maven

# Install modules individually to break cyclic dependency
- name: Install parent POM
run: mvn install -B -N -Djbct.skip=true

- name: Install jbct-core
run: mvn install -B -DskipTests -pl jbct-core -Djbct.skip=true

- name: Install jbct-maven-plugin
run: mvn install -B -DskipTests -pl jbct-maven-plugin -Djbct.skip=true

- name: Build
run: mvn package -DskipTests -Djbct.skip -B
run: mvn package -B -DskipTests -pl jbct-cli -Djbct.skip=true

- name: Create or update release
env:
Expand Down
66 changes: 49 additions & 17 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,57 @@
# Changelog

## [0.6.0] - 2026-01-29

### Added
- Init: groupId validation for `jbct init -g` parameter (validates Java package name format)

### Changed
- Slice init: added tinylog dependencies (2.7.0) in test scope
- Slice init: added tinylog.properties configuration file in test resources
- Build: Bump Aether to 0.8.1
- CI: Re-enabled slice-processor-tests module
- Slice init: Java version 21 to 25
- Slice init: updated default versions (Pragmatica Lite 0.11.1, Aether 0.8.1, JBCT 0.6.0)
- Slice init: implementation pattern changed to record-based (nested record in interface)
- Slice init: removed Config dependency from template (factory now parameterless)
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Changelog entry likely conflicts with the intended template signature.

Line 16 says the factory is now parameterless, but the PR objectives explicitly mention the factory static method accepts a Config dependency parameter. Please confirm the actual template change and adjust the entry accordingly to avoid misleading release notes.

🤖 Prompt for AI Agents
In `@CHANGELOG.md` at line 16, Update the changelog entry to reflect the actual
template factory signature: confirm whether the slice template's static factory
method still accepts a Config parameter or is now parameterless, and then edit
the line "Slice init: removed Config dependency from template (factory now
parameterless)" to accurately state the change (e.g., "Slice init: factory now
accepts Config parameter" or "Slice init: removed Config dependency; factory is
now parameterless") so it matches the implementation of the factory static
method and the Config dependency.

- Slice init: added annotation processor configuration to maven-compiler-plugin
- Slice init: added compilerArgs with `-Aslice.groupId` and `-Aslice.artifactId`
- Slice init: removed separate *Impl.java, SampleRequest.java, SampleResponse.java files
- Slice init: Request/Response/Error records now nested in @Slice interface
- Slice init: removed "Sample" prefix from Request/Response records
- Slice init: inner implementation record uses lowercased slice name, not "Impl"
- Init: version resolution uses running binary version as minimum (overrides GitHub API if newer)
- Init: version comparison uses Result-based `Number.parseInt()` from pragmatica-lite

### Fixed
- RFC-0004 compliance: removed non-standard slice-api.properties generation
- RFC-0004 compliance: slice manifests now include `slice.interface` property
- RFC-0004 compliance: renamed `impl.artifactId` to `slice.artifactId` in manifests
- RFC-0007 compliance: infrastructure dependencies now accessed via InfraStore instead of being proxied
- CollectSliceDepsMojo: now scans META-INF/slice/*.manifest instead of slice-api.properties
- VerifySliceMojo: validates manifest files instead of slice-api.properties
- PackageSlicesMojo: reads slice metadata from .manifest files
- SliceProjectValidator: checks for .manifest files instead of slice-api.properties
- SliceManifest: reads `slice.artifactId` property (was incorrectly reading `impl.artifactId`)
Comment on lines +26 to +35
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Potential spec/backward-compat break: removal of slice-api.properties.

The changelog states slice-api.properties generation was removed in favor of manifests. If any tooling or RFC still requires META-INF/slice-api.properties, this is a breaking change and should be called out (or the removal reconsidered). Please confirm the current canonical requirement and update the changelog (or tooling) accordingly. Based on learnings: “Slice API manifest must be generated at META-INF/slice-api.properties mapping artifact to slice interface.”

🤖 Prompt for AI Agents
In `@CHANGELOG.md` around lines 26 - 35, The changelog removal of
slice-api.properties may be a breaking change for consumers expecting
META-INF/slice-api.properties; update either the release notes or the code to
preserve compatibility: either (A) explicitly document the breaking change in
CHANGELOG.md and state the new canonical requirement (manifests at
META-INF/slice/*.manifest and that slice-api.properties is deprecated/removed),
or (B) restore generation of META-INF/slice-api.properties (ensuring
CollectSliceDepsMojo, VerifySliceMojo, PackageSlicesMojo, SliceProjectValidator
and SliceManifest continue to read/produce it) and mark manifests as the
preferred format; choose one and make matching changes to the changelog and the
implementations (references: slice-api.properties, META-INF/slice/*.manifest,
CollectSliceDepsMojo, VerifySliceMojo, PackageSlicesMojo, SliceProjectValidator,
SliceManifest).

- PackageSlicesMojo: fixed JAR naming bug (empty artifact prefix in JAR names)
- PackageSlicesMojo: fixed JAR overwriting bug (multiple slices now create separate JARs)
- FactoryClassGenerator: infrastructure deps (CacheService, etc.) now use InfraStore.instance().get()
- FactoryClassGenerator: only slice dependencies are proxied via SliceInvokerFacade
- FactoryClassGenerator: reduced flatMap chain depth (e.g., 13 to 3 for UrlShortener with mixed deps)
- PackageSlicesMojo: bytecode transformation replaces UNRESOLVED versions with actual versions (strips semver prefix ^/~)
- Slice init: `ValidationError` now extends `Cause` (required for `Result.failure`)
- Slice init: added missing `Cause` import to template
- Slice init: `Promise.success()` instead of `Promise.successful()`
- Slice init: implemented `message()` method in `ValidationError.EmptyValue`
- Slice init: test template now uses monadic composition instead of `.unwrap()`
- FactoryClassGenerator: infra flatMaps now use proper nesting for variable scoping
- GenerateBlueprintMojo: UNRESOLVED dependency edges now properly resolved in graph traversal
- CollectSliceDepsMojo: improved base.artifact validation (rejects spaces, slashes)

## [0.5.0] - 2026-01-20

### Added
- Security: `SecurityError` sealed interface with `PathTraversal`, `InvalidUrl`, `UntrustedDomain` error types
- Security: `SecurityError` sealed interface with `PathTraversalDetected`, `UrlRejected`, `DomainRejected` error types
- Slice verify: dependency scope validation for Aether runtime libraries
- `jbct:verify-slice` now fails if `org.pragmatica-lite` or `org.pragmatica-lite.aether` dependencies are not `provided` scope
- Prevents accidental bundling of runtime libraries in slice JARs
Expand Down Expand Up @@ -110,8 +158,6 @@

## [0.4.7] - 2026-01-10

### Added

### Changed
- Build: bump Pragmatica Lite to 0.9.10
- Docs: update README with missing CLI options (--config, --version, --artifact-id, etc.)
Expand All @@ -128,8 +174,6 @@

## [0.4.6] - 2026-01-05

### Added

### Changed
- Build: bump Pragmatica Lite to 0.9.7
- Slice processor: refactored models to use `Result<T>` instead of exceptions (JBCT compliance)
Expand All @@ -148,23 +192,15 @@

## [0.4.5] - 2026-01-02

### Added

### Changed
- Build: bump Pragmatica Lite to 0.9.4

### Fixed

## [0.4.4] - 2026-01-01

### Added

### Changed
- AI tools: update to JBCT v2.0.10 with Pragmatica Lite Core 0.9.3
- Build: bump Pragmatica Lite to 0.9.3

### Fixed

## [0.4.3] - 2025-12-31

### Added
Expand All @@ -188,10 +224,6 @@

## [0.4.2] - 2025-12-30

### Added

### Changed

### Fixed
- Parser: `record` as contextual keyword - works as method name, type name, field type, variable type

Expand Down
190 changes: 176 additions & 14 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,36 @@ Relevant RFCs:

To invoke: Use the `/jbct` skill or spawn the `jbct-coder` agent via the Task tool.

## Versioning Policy

Until release 1.0, backward compatibility is not guaranteed. Breaking changes are acceptable for JBCT compliance improvements.

## JBCT Pattern Exceptions

The following deviations from strict JBCT patterns are accepted in this codebase:

### Resource Loading Null Checks

Classpath resource loading uses direct null checks instead of Option pattern due to try-with-resources complexity:

```java
try (var in = Class.class.getResourceAsStream(path)) {
if (in == null) {
return Causes.cause("Resource not found").result();
}
// use stream
}
```

**Affected files:**
- `JarInstaller.java:226` - Copying wrapper scripts
- `ProjectInitializer.java:189` - Loading templates
- `SliceProjectInitializer.java:226` - Loading templates
- `GitHubVersionResolver.java:55` - Loading version properties
- `Version.java:18` - Loading version properties

**Rationale:** Wrapping InputStream in Option requires splitting into two methods to handle try-with-resources correctly. The added complexity outweighs the benefit for adapter-layer code.

## Project Overview
CLI tool and Maven plugin for JBCT (Java Backend Coding Technology) code formatting and linting.

Expand All @@ -37,6 +67,7 @@ jbct-cli/
jbct format <path> # Format Java files
jbct lint <path> # Analyze for JBCT compliance
jbct check <path> # Format check + lint (for CI)
jbct score <path> # Calculate JBCT compliance score (0-100)
jbct upgrade # Update CLI from GitHub Releases
jbct init [dir] # Create new JBCT project + install AI tools
jbct init --slice [dir] # Create new Aether slice project
Expand Down Expand Up @@ -68,11 +99,121 @@ JBCT-RET-01 = "error"
JBCT-VO-01 = "warning"
```

## JBCT Compliance Scoring

The `jbct score` command calculates a 0-100 compliance score based on lint violations across 6 weighted categories.

### Usage

```bash
# CLI
jbct score <path> # Terminal output with progress bars
jbct score --format json <path> # JSON output
jbct score --format badge <path> # SVG badge
jbct score --baseline 75 <path> # Fail if score < 75

# Maven
mvn jbct:score
mvn jbct:score -Djbct.score.baseline=75
```

### Scoring Formula

**Category score:**
```
weighted_violations = Σ(count[severity] × multiplier[severity])
ERROR: × 2.5
WARNING: × 1.0
INFO: × 0.3

category_score = 100 × (1 - weighted_violations / checkpoints)
```

**Overall score:**
```
overall_score = Σ(category_score[i] × weight[i])
```

### Scoring Categories

| Category | Weight | Rules Included |
|--------------------|--------|----------------|
| Return Types | 25% | JBCT-RET-01, JBCT-RET-02, JBCT-RET-03, JBCT-NEST-02, JBCT-RES-01 |
| Null Safety | 20% | JBCT-NULL-01, JBCT-NULL-02 |
| Exception Hygiene | 20% | JBCT-EXC-01, JBCT-EXC-02, JBCT-NAME-02 |
| Pattern Purity | 15% | JBCT-PAT-01, JBCT-NEST-01, JBCT-CHAIN-01, JBCT-IMPORT-01, JBCT-FQN-01, JBCT-DOMAIN-01, JBCT-LOOP-01, JBCT-LOG-01, JBCT-LOG-02 |
| Factory Methods | 10% | JBCT-VO-01, JBCT-VO-02, JBCT-VO-03, JBCT-VO-04, JBCT-ERR-01, JBCT-NAME-01, JBCT-PARSE-01 |
| Lambda Compliance | 10% | JBCT-LAM-01, JBCT-LAM-02, JBCT-LAM-03, JBCT-LAM-04, JBCT-STATIC-01 |

### Output Formats

**Terminal** (default):
```
╔═══════════════════════════════════════════════════╗
║ JBCT COMPLIANCE SCORE: 85/100 ║
╠═══════════════════════════════════════════════════╣
║ RETURN TYPES █████████████████░░░ 85% ║
║ NULL SAFETY ████████████████░░░░ 80% ║
║ EXCEPTION HYGIENE ██████████████████░░ 90% ║
║ PATTERN PURITY ███████████████░░░░░ 75% ║
║ FACTORY METHODS ████████████████████ 100% ║
║ LAMBDA COMPLIANCE ██████████████████░░ 90% ║
╚═══════════════════════════════════════════════════╝
```

**JSON**:
```json
{
"score": 85,
"breakdown": {
"return_types": 85,
"null_safety": 80,
"exception_hygiene": 90,
"pattern_purity": 75,
"factory_methods": 100,
"lambda_compliance": 90
},
"filesAnalyzed": 42
}
```

**Badge** (SVG):
- Color: green (≥75), yellow (≥60), orange (≥50), red (<50)
- Format: `JBCT | 85/100`

### CI Integration

Use `--baseline` to enforce minimum score in CI:

```bash
jbct score --baseline 75 src/main/java || exit 1
```

Or with Maven:

```xml
<plugin>
<groupId>org.pragmatica-lite</groupId>
<artifactId>jbct-maven-plugin</artifactId>
<version>0.6.0</version>
<executions>
<execution>
<goals>
<goal>score</goal>
</goals>
<configuration>
<baseline>75</baseline>
</configuration>
</execution>
</executions>
</plugin>
```

## Key Dependencies

- **pragmatica-lite:core** (0.9.10) - Result, Option, Promise types
- **pragmatica-lite:http-client** (0.9.10) - HTTP operations for upgrade/update
- **pragmatica-lite:toml** (0.9.10) - TOML configuration parsing
- **pragmatica-lite:core** (0.11.2) - Result, Option, Promise types
- **pragmatica-lite:http-client** (0.11.2) - HTTP operations for upgrade/update
- **pragmatica-lite:toml** (0.11.2) - TOML configuration parsing
- **java-peglib** - PEG parser generator for CST-based parsing
- **picocli** - CLI framework

Expand Down Expand Up @@ -181,27 +322,37 @@ http.sendString(request)

## Build Commands

**Important**: This project uses its own jbct-maven-plugin (dogfooding), creating a dependency cycle. All reactor builds require `-Djbct.skip=true` to avoid the cycle error.

```bash
# Compile
mvn compile
mvn compile -Djbct.skip=true

# Run tests
mvn test
mvn test -Djbct.skip=true

# Build distribution (creates tar.gz/zip)
mvn package -DskipTests
mvn package -DskipTests -Djbct.skip=true

# Full verify (includes jbct:check)
mvn verify
# Full verify
mvn verify -Djbct.skip=true

# Format all source files
mvn jbct:format
# Format all source files (run on single module)
mvn jbct:format -pl jbct-core

# Check formatting and lint
mvn jbct:check
# Check formatting and lint (run on single module)
mvn jbct:check -pl jbct-core
```

**Note**: This project uses its own jbct-maven-plugin (dogfooding). The `jbct:check` goal runs automatically during `mvn verify`.
### Installing to Local Repository

Due to the dependency cycle, install modules individually:

```bash
mvn install -DskipTests -pl jbct-core -Djbct.skip=true
mvn install -DskipTests -pl jbct-maven-plugin -Djbct.skip=true
mvn install -DskipTests -pl jbct-cli,slice-processor,slice-processor-tests -Djbct.skip=true
```

## Distribution

Expand Down Expand Up @@ -340,7 +491,18 @@ Note: Proxy records for dependencies are generated as local records inside the f

### HTTP Routing Generation

When `routes.toml` exists in the slice package resources, generates HTTP route handling:
When `routes.toml` exists in the slice package resources, generates HTTP route handling.

**Dependency requirement**: New projects created with `jbct init --slice` include `http-routing-adapter` automatically. For existing projects adding routing, add:
```xml
<dependency>
<groupId>org.pragmatica-lite.aether</groupId>
<artifactId>http-routing-adapter</artifactId>
<version>${aether.version}</version>
<scope>provided</scope>
</dependency>
```
Compilation fails if `routes.toml` exists without this dependency.

**Config location:** `src/main/resources/{slicePackage}/routes.toml`

Expand Down
Loading