This is an automated email from the ASF dual-hosted git repository.

jamesbognar pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/juneau.git


The following commit(s) were added to refs/heads/master by this push:
     new 7184eb62bb Stop tracking AGENTS.md and .cursor; ignore locally
7184eb62bb is described below

commit 7184eb62bb5965098aa0e1a870bed5738b58bdc9
Author: James Bognar <[email protected]>
AuthorDate: Sat Apr 18 08:08:47 2026 -0400

    Stop tracking AGENTS.md and .cursor; ignore locally
    
    Remove Cursor/AI assistant config from the Apache source tree while
    keeping paths ignored so developers can retain them locally.
    
    Made-with: Cursor
---
 .cursor/skills/push/SKILL.md |   24 -
 .cursor/skills/todo/SKILL.md |   20 -
 .gitignore                   |    4 +
 AGENTS.md                    | 1650 ------------------------------------------
 4 files changed, 4 insertions(+), 1694 deletions(-)

diff --git a/.cursor/skills/push/SKILL.md b/.cursor/skills/push/SKILL.md
deleted file mode 100644
index 72f5cb676c..0000000000
--- a/.cursor/skills/push/SKILL.md
+++ /dev/null
@@ -1,24 +0,0 @@
----
-name: push
-description: Push Changes
-disable-model-invocation: true
----
-# Push Changes
-
-Run the Juneau push script to build, test, commit, and push changes. You will 
determine the commit message yourself based on the staged/changed files.
-
-## Steps
-
-1. **Inspect changes**: Run `git status` and `git diff --staged` (or `git 
diff` if nothing staged) to see what has changed.
-2. **Determine commit message**: Based on the changes, craft a clear, 
descriptive commit message. Follow conventional commit style when appropriate 
(e.g., `fix:`, `feat:`, `refactor:`, `docs:`). Keep it concise but specific.
-3. **Run push script**: Execute from the project root (master/):
-
-   ```
-   python3 scripts/push.py "YOUR_COMMIT_MESSAGE"
-   ```
-
-   Use `--skip-tests` only for documentation-only changes. Do not use 
`--dry-run` unless the user asks.
-
-4. **Report result**: Summarize what was committed and pushed, or report any 
failures.
-
-Do not ask the user for the commit message—determine it from the changes 
yourself.
diff --git a/.cursor/skills/todo/SKILL.md b/.cursor/skills/todo/SKILL.md
deleted file mode 100644
index d67a993450..0000000000
--- a/.cursor/skills/todo/SKILL.md
+++ /dev/null
@@ -1,20 +0,0 @@
----
-name: todo
-description: Add to TODO
-disable-model-invocation: true
----
-# Add to TODO
-
-Add an entry to `TODO.md` in the project root.
-
-## Steps
-
-1. **Get the TODO text**: Use the text the user provides after `/todo` as the 
new TODO entry. If no text is given, ask what they would like to add.
-2. **Read TODO.md**: Check the current format and existing entries.
-3. **Add the entry**: Append a new bullet to the list, matching the existing 
format:
-   ```
-   - [description of the TODO]
-   ```
-4. **Confirm**: Tell the user the entry was added.
-
-Keep the description clear and actionable. Do not add TODO-# identifiers to 
the list—those are only used when referencing items for "work on TODO-X" 
commands.
diff --git a/.gitignore b/.gitignore
index 4210a16677..96753ce8b8 100644
--- a/.gitignore
+++ b/.gitignore
@@ -10,6 +10,10 @@ derby.log
 # Temporary cursor assistant scripts
 cursor-*
 
+# Local Cursor / AI assistant config (not part of Apache source tree)
+AGENTS.md
+.cursor/
+
 # Maven Shade Plugin generated files
 **/dependency-reduced-pom.xml
 
diff --git a/AGENTS.md b/AGENTS.md
deleted file mode 100644
index 1ee7343b88..0000000000
--- a/AGENTS.md
+++ /dev/null
@@ -1,1650 +0,0 @@
-# AI Assistant Rules for Apache Juneau
-
-This document outlines the rules, guidelines, and best practices that AI 
assistants follow when working on the Apache Juneau project.
-
-**Note**: This file is referred to as "my rules" and serves as the definitive 
reference for all guidelines and conventions I follow when working on the 
Apache Juneau project.
-
-**Important**: Also read `AI_SESSION.md` to understand the current session's 
work context, what we're currently working on, and any recent changes or 
patterns established in this session.
-
-**Documentation Separation Rule**: `AI_SESSION.md` should only contain 
session-specific information that is not already covered in `AGENTS.md`. 
General rules, permanent conventions, and best practices belong in `AGENTS.md`. 
Session-specific work progress, current tasks, and temporary patterns belong in 
`AI_SESSION.md`.
-
-## User Commands
-
-### Shorthand Commands
-- **"c"** means **"continue"** - When the user sends just "c", continue with 
the current task or work
-- **"s"** means **"status"** - When the user sends just "s", give a status 
update on what you're currently working on
-- **"TODO-x"** means **"work on this TODO"** - When the user sends just 
"TODO-3", "TODO-67", etc., start working on that specific TODO item from the 
`/todo/TODO.md` file
-
-### Task Interpretation Commands
-- **"make a plan"** or **"come up with a plan"** - When the user asks to make 
a plan for something, provide a summary of suggested changes only. **Do NOT 
make actual code changes**. The plan should outline what needs to be done, but 
implementation should wait for explicit user approval.
-- **"suppress warnings"** or **"suppress issues"** - When the user asks to 
suppress warnings or issues that appear to refer to SonarLint/SonarQube issues, 
add `@SuppressWarnings` annotations to the appropriate class or method level. 
Use the specific rule ID from the warning (e.g., `java:S100`, `java:S115`, 
`java:S116`). Apply class-level suppressions when multiple methods/fields are 
affected, or method-level suppressions for specific methods.
-- **SuppressWarnings Format**: All `@SuppressWarnings` annotations must use 
multi-line format with curly braces and include a brief comment explaining why 
each suppression is needed. Never use single-line `@SuppressWarnings("xxx")` 
without the multi-line format and comment.
-  ```java
-  @SuppressWarnings({
-      "resource" // CsvReader owns ParserReader; caller must close CsvReader
-  })
-  ```
-  Or for multiple suppressions:
-  ```java
-  @SuppressWarnings({
-      "rawtypes", // Raw types necessary for generic type handling
-      "unchecked", // Type erasure requires unchecked casts
-      "resource" // w is closed by try-with-resources; lambdas capture it
-  })
-  ```
-  **Exception**: Parameter-level annotations (e.g. `catch 
(@SuppressWarnings("unused") Exception e)`) may remain single-line when 
multi-line format is impractical.
-
-### Script Shortcut Commands
-- **"start docs"** or **"start docusaurus"** - Runs 
`scripts/start-docusaurus.py`
-- **"revert staged"** - Runs `scripts/revert-staged.py`
-- **"revert unstaged"** - Runs `scripts/revert-unstaged.py`
-- **"start jetty"** - Runs `scripts/start-examples-rest-jetty.py`
-- **"start springboot"** - Runs `scripts/start-examples-springboot.py`
-- **"push"** or **"push changes"** - When the user asks to push changes, use 
`./scripts/push.py "Commit message"` to push changes. **Always prompt the user 
for the commit message** and provide 2-3 suggested commit message options based 
on the changes made. Example: `./scripts/push.py "Replace 
Stream.collect(Collectors.toList()) with Stream.toList()"`
-- **"test"** - Runs `scripts/test.py`
-
-### Documentation Commands
-- **"save a rule"** or **"save this rule"** - Add the rule/information to 
`AGENTS.md` (permanent/general)
-- **"store this rule in the session"** - Add the rule/information to 
`AI_SESSION.md` (session-specific)
-- **"store this rule in the context"** - Add the rule/information to 
`AGENTS.md` (permanent/general)
-
-## Core Working Principles
-
-### 0. Change Evaluation
-- After each code modification, provide a brief (1-2 sentence) evaluation of 
the change
-- Explain what was changed and why it improves the codebase
-- This helps document the reasoning behind modifications and ensures changes 
are intentional
-
-### 1. Code Quality and Consistency
-- Follow existing code patterns and conventions
-- Maintain consistency with the existing codebase
-- Use established naming conventions and formatting
-- Preserve existing functionality while making improvements
-
-#### Indentation Rules
-When adding or modifying Java code, **ALWAYS** preserve the exact indentation 
of the surrounding code:
-
-**Critical Requirements:**
-1. **Use tabs, not spaces** - Java files in this project use tab characters 
for indentation
-2. **Match surrounding code exactly** - Copy the leading whitespace 
character-for-character from the `old_string`
-3. **Preserve indentation levels** - Count tabs in nearby lines and use the 
same number
-
-**Common Patterns:**
-```java
-<TAB>/**
-<TAB> * Javadoc line 1
-<TAB> * Javadoc line 2
-<TAB> */
-<TAB>@Annotation
-<TAB>public ReturnType methodName() {
-<TAB><TAB>return statement;
-<TAB>}
-```
-
-Where `<TAB>` represents an actual tab character (`\t`), not spaces.
-
-**Why This Matters:**
-- Incorrect indentation (offset by one tab to the left) is a common error
-- Mixed tabs/spaces cause inconsistent formatting
-- IDE auto-formatting relies on consistent indentation
-- Project standards mandate tab-based indentation
-
-**Verification Steps:**
-1. Before creating `new_string`, examine the indentation in `old_string`
-2. Count the tab characters at the start of each line
-3. Copy the exact indentation pattern (including all tabs)
-4. For new Javadoc, match the indentation of nearby methods
-
-**Example Correction:**
-```java
-// WRONG - Missing leading tab
-/**
- * Method description
- */
-public void method() {
-
-// CORRECT - Includes leading tab
-<TAB>/**
-<TAB> * Method description
-<TAB> */
-<TAB>public void method() {
-```
-
-#### Exception Handling
-When throwing exceptions in Java code:
-
-1. **Use `ThrowableUtils` methods** instead of direct exception constructors:
-   - Use `illegalArg(String message, Object... args)` for 
`IllegalArgumentException`
-   - Use `runtimeException(String message, Object... args)` for generic 
`RuntimeException`
-   - Add static import: `import static 
org.apache.juneau.common.utils.ThrowableUtils.*;`
-
-2. **Use MessageFormat-style placeholders** with `ThrowableUtils` methods:
-   - Use `{0}`, `{1}`, etc. for parameter placeholders
-   - Escape single quotes with `''` (e.g., `"Value ''{0}'' is invalid"`)
-   - Pass arguments as varargs after the message string
-
-**Examples:**
-```java
-// WRONG - Direct exception constructor
-throw new IllegalArgumentException("Value '" + value + "' is invalid");
-
-// CORRECT - ThrowableUtils with MessageFormat
-throw illegalArg("Value ''{0}'' is invalid", value);
-
-// WRONG - String concatenation
-throw new RuntimeException("Failed to process " + name + " with id " + id);
-
-// CORRECT - ThrowableUtils with multiple arguments
-throw runtimeException("Failed to process {0} with id {1}", name, id);
-```
-
-#### Local Variable Type Inference
-When declaring local variables in Java code:
-
-1. **Use the `var` keyword** whenever the type is obvious from the right-hand 
side:
-   - Initializers with constructor calls: `var map = new 
HashMap<String,Integer>();`
-   - Method calls with clear return types: `var list = getList();`
-   - Stream operations: `var result = stream.collect(toList());`
-   - Enhanced for loops: `for (var entry : map.entrySet())`
-
-2. **Keep explicit types** when:
-   - The type is not obvious from the initializer: `InputStream stream = 
getStream();`
-   - Readability would suffer: `boolean hasNext = iterator.hasNext();` (better 
than `var hasNext`)
-   - Generic type parameters need to be preserved on left side: `List<String> 
list = new ArrayList<>();`
-
-**Examples:**
-```java
-// WRONG - Redundant type declaration
-Map<String,Integer> map = new HashMap<String,Integer>();
-List<String> keys = map.keySet();
-
-// CORRECT - Use var
-var map = new HashMap<String,Integer>();
-var keys = map.keySet();
-```
-
-#### Instanceof Pattern Matching Variable Naming
-When using instanceof pattern matching (Java 16+), follow this naming 
convention:
-
-1. **General Rule**: Append "2" to the original variable name:
-   - `if (o instanceof Type o2)` - original variable is `o`, pattern variable 
is `o2`
-   - `if (value instanceof Calendar value2)` - original variable is `value`, 
pattern variable is `value2`
-   - `if (this instanceof MethodInfo this2)` - original variable is `this`, 
pattern variable is `this2`
-
-2. **Exception for variables ending in "2"**: When the original variable 
already ends in "2" (like `o2`), use "o3" instead of "o22" for simplicity:
-   - `if (o2 instanceof InputStream o3)` - original variable is `o2`, pattern 
variable is `o3`
-   - `if (o1 instanceof Comparable o3)` - original variable is `o1`, pattern 
variable is `o3` (not `o12`)
-
-3. **Conflict Resolution**: When there's a naming conflict (e.g., a lambda 
parameter with the same name), use a different name:
-   - `if (value instanceof BeanMap<?> value2)` followed by 
`value2.forEachValue(..., (pMeta2, key2, value3, thrown2) -> ...)` - lambda 
parameter uses `value3` to avoid conflict with pattern variable `value2`
-
-**Examples:**
-```java
-// CORRECT - Standard pattern
-if (o instanceof BeanMap o2)
-    serializeBeanMap(out, o2, typeName);
-
-// CORRECT - Variable ending in "2"
-for (var o2 : o) {
-    if (o2 instanceof InputStream o3)
-        o3.close();
-}
-
-// CORRECT - Conflict resolution
-if (value instanceof BeanMap<?> value2) {
-    value2.forEachValue(x -> true, (pMeta2, key2, value3, thrown2) -> {
-        // value3 used to avoid conflict with value2
-    });
-}
-
-// WRONG - Not following convention
-if (o instanceof BeanMap bm)  // Should be o2
-if (value instanceof Calendar cal)  // Should be value2
-```
-
-#### Final Fields and Memoization Pattern
-When declaring class fields, always use `final` to ensure true immutability:
-
-1. **Always use `final` for fields**:
-   - All instance fields should be declared `final` whenever possible
-   - This provides compile-time immutability guarantees
-   - Prevents accidental modification after construction
-
-2. **Use `find` helper methods for memoized fields**:
-   - When memoized `Supplier` fields need constructor parameters, use helper 
methods
-   - Name helper methods with the `find` prefix (e.g., 
`findGenericInterfaces()`)
-   - Helper methods are called during field initialization and can access 
constructor parameters
-   - This allows final fields to depend on constructor parameters
-
-3. **Why this matters:**
-   - Provides stronger immutability guarantees than "effectively final" 
comments
-   - Compiler enforces immutability rather than relying on conventions
-   - Makes the code more maintainable and less error-prone
-   - Documents thread-safety guarantees explicitly
-
-**Examples:**
-```java
-// WRONG - Non-final field with comment
-Class<?> c;  // Effectively final
-
-// CORRECT - Final field with helper method pattern
-public class ClassInfo {
-       private final Class<?> c;
-       
-       // Final supplier initialized using helper method that accesses 
constructor parameter
-       private final Supplier<List<Type>> genericInterfacesCache = 
memoize(this::findGenericInterfaces);
-       
-       public ClassInfo(Class<?> c) {
-               this.c = c;
-       }
-       
-       // Helper method called during field initialization
-       private List<Type> findGenericInterfaces() {
-               return c == null ? Collections.emptyList() : 
u(l(c.getGenericInterfaces()));
-       }
-}
-```
-
-**Pattern Summary:**
-1. Declare constructor parameters as `final` fields
-2. Create `find` helper methods that use those fields
-3. Initialize memoized `Supplier` fields with method references to the helper 
methods
-4. This allows all fields to be truly `final` while still supporting lazy 
initialization
-
-#### Git Operations and Reverts
-When working with git operations, especially reverting changes:
-
-1. **Use helper scripts for reverting** - Always use the provided Python 
scripts instead of git commands directly:
-   - ✅ CORRECT: `./scripts/revert-unstaged.py path/to/specific/File.java` 
(reverts unstaged to staged)
-   - ✅ CORRECT: `./scripts/revert-staged.py path/to/specific/File.java` 
(reverts to HEAD, discards all changes)
-   - ❌ WRONG: Using `git restore`, `git checkout`, or any git commands directly
-
-2. **Revert Unstaged Changes Script** - `./scripts/revert-unstaged.py`
-   - Reverts working directory changes back to the staged (INDEX) version
-   - Preserves staged changes that have been tested
-   - Use this when you have staged changes you want to keep
-   - Command: `git restore --source=INDEX <file>`
-
-3. **Revert Staged Changes Script** - `./scripts/revert-staged.py`
-   - Reverts both staged AND unstaged changes back to HEAD (last commit)
-   - ⚠️  WARNING: Discards all changes (staged and unstaged)
-   - Use this when you want to completely discard all changes to a file
-   - Command: `git restore --source=HEAD <file>`
-
-4. **Always revert one file at a time** - Never use broad wildcards or 
multiple file paths:
-   - ✅ CORRECT: `./scripts/revert-unstaged.py path/to/specific/File.java`
-   - ❌ WRONG: Reverting multiple files or using wildcards
-
-5. **Why this matters:**
-   - **Preserves staged changes**: Staged changes have been tested and should 
not be lost
-   - **Surgical precision**: Only reverts the specific problematic file's 
changes
-   - **Safe recovery**: If a file is staged, it means it was working at that 
point
-   - **Prevents data loss**: Won't accidentally revert good changes along with 
bad ones
-   - **User-friendly**: Scripts provide clear feedback and prevent common 
mistakes
-
-6. **Proper workflow when compilation fails:**
-   - Identify the specific file(s) causing the error
-   - Revert only that file's unstaged changes: `./scripts/revert-unstaged.py 
path/to/ProblematicFile.java`
-   - Verify the revert fixed the issue (back to staged/tested version)
-   - Then address that specific file's changes separately
-
-**Examples:**
-```bash
-# CORRECT - Revert unstaged changes only (preserves staged)
-./scripts/revert-unstaged.py 
juneau-core/juneau-marshall/src/main/java/org/apache/juneau/objecttools/ObjectSearcher.java
-
-# CORRECT - Revert all changes back to HEAD (discards everything)
-./scripts/revert-staged.py 
juneau-core/juneau-marshall/src/main/java/org/apache/juneau/objecttools/ObjectSearcher.java
-
-# WRONG - Don't use git commands directly
-git restore --source=INDEX path/to/file
-git checkout -- path/to/file
-```
-
-**Understanding the scripts:**
-- `revert-unstaged.py`: Uses `git restore --source=INDEX` to revert to staged 
version
-- `revert-staged.py`: Uses `git restore --source=HEAD` to revert to last commit
-- Both scripts handle one file at a time for safety
-- Both provide clear feedback about what they're doing
-
-### 2. Testing Standards
-- Ensure comprehensive test coverage for all changes
-- Follow the established unit testing patterns
-- Use the Sequential Single-Letter Label Convention (SSLLC)
-- Implement proper assertion patterns using `assertBean()`
-
-### 3. Documentation Standards
-- Maintain comprehensive javadoc documentation
-- Follow established documentation formatting rules
-- Include practical examples in documentation
-- Link to relevant specifications and resources
-
-### 4. Build and Compilation Issues
-
-**IMPORTANT: Maven vs IDE Compilation Divergence**
-
-When compiling code using Maven and the user compiles through their IDE 
(Eclipse), the compiled code can diverge, leading to unexpected behavior such 
as:
-- Code changes not being reflected in test runs
-- Old code behavior persisting despite source changes
-- Stale class files causing incorrect results
-
-**Eclipse "Build Automatically" Setting:**
-The user typically has "Refresh using native hooks or polling" enabled in 
Eclipse, and may or may not have "Build Automatically" enabled.
-
-**If code changes don't appear to be taking effect or are getting 
overwritten:**
-1. **Ask the user to check if "Build Automatically" is enabled** (Project → 
Build Automatically menu)
-2. **If enabled, politely ask them to disable it**: "Could you please disable 
'Build Automatically' in Eclipse (Project → Build Automatically)?"
-3. **Why this matters:**
-   - When "Build Automatically" is enabled, Eclipse may rebuild files 
immediately after saving
-   - This can conflict with Maven builds, causing files to be overwritten
-   - Disabling it gives you more control over when builds occur
-   - The user can manually build when needed using Ctrl+B or Project → Build 
Project
-
-**Resolution Strategy:**
-If you encounter situations where your code changes don't appear to be taking 
effect:
-1. **First, ask about Eclipse "Build Automatically"** and request it be 
disabled if enabled
-2. **Then run** `mvn clean install` to clear all compiled artifacts and 
rebuild fresh
-3. This ensures Maven and IDE compiled code are synchronized
-4. Rerun tests after the clean build to verify changes are properly reflected
-
-**When to suspect this issue:**
-- Tests fail in unexpected ways after code changes
-- Behavior doesn't match recent code modifications
-- Test results seem to reflect old code despite edits
-- Compilation succeeds but runtime behavior is wrong
-- Code changes appear to be getting overwritten or not taking effect
-
-**Java Runtime Location:**
-If you can't find Java on the file system using standard commands, look for it 
in the `~/jdk` folder. For example:
-- Java 17 can be found at: 
`~/jdk/openjdk_17.0.14.0.101_17.57.18_aarch64/bin/java`
-- Use this path when you need to run Java commands directly
-
-### 5. Helper Scripts
-
-**Build and Test Script:**
-A reusable Python script is available at `scripts/test.py` for common Maven 
operations.
-
-**Usage:**
-```bash
-# Default: Clean build + run tests
-./scripts/test.py
-
-# Build only (skip tests)
-./scripts/test.py --build-only
-./scripts/test.py -b
-
-# Test only (no build)
-./scripts/test.py --test-only
-./scripts/test.py -t
-
-# Full build and test (explicit)
-./scripts/test.py --full
-./scripts/test.py -f
-
-# Verbose output (show full Maven output)
-./scripts/test.py --verbose
-./scripts/test.py -v
-
-# Help
-./scripts/test.py --help
-./scripts/test.py -h
-```
-
-**What it does:**
-- `--build-only/-b`: Runs `mvn clean install -q -DskipTests`
-- `--test-only/-t`: Runs `mvn test -q -Drat.skip=true`
-- `--full/-f` (default): Runs both build and test in sequence
-- By default, shows only the last 50 lines of output
-- Use `--verbose/-v` to see full Maven output
-
-**When to use:**
-- Instead of manually typing out Maven commands repeatedly
-- When you need to verify both build and tests pass
-- During iterative development to quickly test changes
-
-### 5.1. Coverage Script
-
-A reusable Python script is available at `scripts/coverage.py` for checking 
JaCoCo test coverage on any source file, package, or module.
-
-**When asked for current test coverage** on a class, package, or module, 
always use this script rather than manually parsing JaCoCo output.
-
-**Usage:**
-```bash
-# Coverage for an entire package
-./scripts/coverage.py 
juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/conversion/
-
-# Coverage for a single file
-./scripts/coverage.py 
juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/conversion/BasicConverter.java
-
-# Show only lines with missed branches (hide instruction-only misses)
-./scripts/coverage.py path/to/file.java --branches
-
-# Re-run tests first to refresh coverage data, then report
-./scripts/coverage.py path/to/folder/ --run
-```
-
-**What it does:**
-- Detects the Maven module automatically from the path
-- Generates a JaCoCo report using the existing 
`juneau-utest/target/jacoco.exec`
-- Displays branch and instruction coverage percentages with a progress bar
-- Lists every uncovered line with the number of missed branches/instructions
-
-**How coverage data works:**
-- The `.exec` file is produced by `juneau-utest` during a test run and covers 
all loaded classes, including those from other modules (e.g. `juneau-commons`)
-- Use `--run` when tests have changed since the last run; omit it to reuse 
existing data for speed
-- Report generation takes ~2 seconds; test execution adds ~10-15 seconds
-
-**Trigger phrases:** When the user says any of the following, run this script:
-- "what's the coverage on ..."
-- "show coverage for ..."
-- "current test coverage"
-- "check coverage"
-- "coverage report"
-
-### 5.3. Command Execution Best Practices
-
-**Adding Timeouts to Commands:**
-
-When running terminal commands that use `head`, `tail`, or pipe operations 
that might hang waiting for input, always wrap them with the `timeout` command 
to prevent indefinite hangs:
-
-1. **Use `timeout` for commands with `head`/`tail`**:
-   - Instead of: `command | grep pattern | head -5`
-   - Use: `timeout 30s sh -c 'command | grep pattern | head -5'`
-
-2. **Timeout durations**:
-   - Quick commands (grep, find, etc.): 10-30 seconds
-   - Maven commands: 60-120 seconds (or longer for full builds)
-   - Adjust based on expected command duration
-
-3. **Why this matters**:
-   - Commands with `head`/`tail` can hang indefinitely if the input stream 
doesn't close
-   - Pipe operations may wait for input that never arrives
-   - Timeouts prevent the assistant from getting stuck waiting for commands 
that will never complete
-
-**Examples:**
-```bash
-# Quick command with timeout
-timeout 10s sh -c 'mvn test-compile 2>&1 | grep "ERROR" | head -5'
-
-# Maven command with longer timeout
-timeout 120s sh -c 'mvn clean install 2>&1 | tail -20'
-```
-
-### 6. Error Handling and Validation
-- Use `assertThrowsWithMessage` for exception testing
-- Test both valid and invalid scenarios
-- Include proper error messages in assertions
-- Test null parameter validation where applicable
-
-### 7. Code Coverage Guidelines
-- Aim for 100% instruction coverage on bean classes
-- Use JaCoCo reports to identify missing coverage
-- Focus on methods with 0% coverage first
-- Add comprehensive tests for all code paths
-- **Hard-to-Test Code Marking**: When a line of code is found to not be fully 
testable (e.g., requires complex setup, compiler-generated code, or unreachable 
branches), add a comment `// HTT` (Hard To Test) on that line to document why 
it's difficult to test
-- **When writing unit tests for new code, always run `coverage.py` afterward 
to identify coverage gaps before moving on.** Use `--run` to refresh the 
`.exec` data after adding new tests:
-  ```bash
-  ./scripts/coverage.py path/to/NewFile.java --run
-  ./scripts/coverage.py path/to/new/package/ --run
-  ./scripts/coverage.py path/to/new/package/ --branches  # show only missed 
branches
-  ```
-
-### 8. File Organization and Naming
-- Follow established file naming conventions
-- Maintain proper package structure
-- Use consistent import organization
-- Follow established class and method naming patterns
-
-### 9. Documentation Links and References
-- Use hardcoded links to `https://juneau.apache.org/docs/topics/`
-- Include specification links for external standards where applicable
-- Use proper cross-references with `{@link}` tags
-- Maintain consistent link formatting
-
-### 10. Systematic Approach
-- Work through tasks systematically and alphabetically when specified
-- Complete tasks without breaks when requested
-- Verify all changes work correctly
-- Maintain consistency across similar files
-
-### 11. TODO List Management
-- When the user says "add to TODO" or "add to the TODO list", this refers to 
the `TODO.md` file in the `/todo` folder
-- Do NOT use the in-memory todo list tool for user-requested TODO items
-- Add items directly to the `/todo/TODO.md` file using the write or 
search_replace tools
-- Follow the existing format and structure of the TODO.md file
-- **TODO Identifiers**: When adding new TODO items, assign them a unique 
"TODO-#" identifier (e.g., "TODO-1", "TODO-2", etc.)
-- **TODO References**: When the user asks to "fix TODO-X" or "work on TODO-X", 
they are referring to the specific identifier in the TODO.md file
-- **TODO Completion**: When TODOs are completed, remove them from the TODO 
list entirely
-- **Plans**: Implementation plans (e.g., `1_ini_implementation.md`, 
`2_hjson_implementation.md`) are also located in the `/todo` folder alongside 
TODO.md
-
-### 12. Release Notes Management
-- When the user says "add to release notes" or "add this to the release 
notes", this refers to the release notes in the `/juneau-docs` directory
-- Do NOT add to the root `RELEASE-NOTES.txt` file
-- For the current release (9.2.0), add entries to `/juneau-docs/9.2.0.md`
-- Follow the existing format and structure of the release notes in juneau-docs
-- Use the same formatting style as other entries in the release notes file
-
-### 13. Fluent Setter Override Formatting
-When adding fluent setter overrides to classes:
-- Include blank lines between each method
-- Each override method should be separated by exactly one blank line
-- Example pattern:
-  ```java
-  @Override /* Overridden from ParentClass */
-  public ChildClass setProperty1(Type value) {
-      super.setProperty1(value);
-      return this;
-  }
-
-  @Override /* Overridden from ParentClass */
-  public ChildClass setProperty2(Type value) {
-      super.setProperty2(value);
-      return this;
-  }
-  ```
-- **Rationale**: Maintains consistency with existing code style and improves 
readability
-
-#### properties() Method Formatting
-When creating a `properties()` method that uses the fluent map API with `.a()` 
method calls:
-
-1. **Always use `Utils.filteredBeanPropertyMap()`**: Use 
`filteredBeanPropertyMap()` to create the map. This method provides sorted, 
filtered, fluent maps specifically designed for bean property maps.
-2. **Wrap in formatter comments**: Wrap the entire method contents inside `// 
@formatter:off` and `// @formatter:on` comments to preserve formatting
-
-```java
-protected FluentMap<String,Object> properties() {
-       // @formatter:off
-       return filteredBeanPropertyMap()
-               .a("property1", value1)
-               .a("property2", value2)
-               .a("property3", value3);
-       // @formatter:on
-}
-```
-
-**Rationale**: 
-- `filteredBeanPropertyMap()` automatically provides sorted entries, filtered 
values (removes empty/null values), and a fluent API
-- Ensures consistent ordering for deterministic output
-- Provides a clean, dedicated API for building bean property maps
-- Formatter comments preserve the formatting of fluent method chains and 
prevent formatters from reformatting the code in ways that reduce readability
-
----
-
-# Documentation Guidelines for Apache Juneau
-
-This document outlines the documentation conventions, formatting rules, and 
best practices for the Apache Juneau project.
-
-## Javadoc Formatting Standards
-
-### HTML Tags and Formatting
-
-**Java Variables in Examples**:
-- Wrap local Java variables in `<jv>` tags
-- Example: `<jv>json</jv>`, `<jv>swagger</jv>`, `<jv>result</jv>`
-
-**Static Method References**:
-- Use `<jsm>` tags for static method names
-- Example: `Json.<jsm>from</jsm>(<jv>x</jv>)`
-
-**Static Field References**:
-- Use `<jsf>` tags for static field names
-- Example: `JsonSerializer.<jsf>DEFAULT</jsf>`
-
-**Code Comments**:
-- Use `<jc>` tags for code comments
-- Example: `<jc>// Serialize using JsonSerializer.</jc>`
-
-**Class References**:
-- Use `<jk>` tags for class names in text
-- Example: `<jk>null</jk>`, `<jk>String</jk>`
-
-### Syntax Highlighting Tags (from juneau-code.css)
-
-**Java Code Tags**:
-- `<jc>` - Java comment (green)
-- `<jd>` - Javadoc comment (blue)
-- `<jt>` - Javadoc tag (blue, bold)
-- `<jk>` - Java keyword (purple, bold)
-- `<js>` - Java string (blue)
-- `<jf>` - Java field (dark blue)
-- `<jsf>` - Java static field (dark blue, italic)
-- `<jsm>` - Java static method (italic)
-- `<ja>` - Java annotation (grey)
-- `<jp>` - Java parameter (brown)
-- `<jv>` - Java local variable (brown)
-
-**XML Code Tags**:
-- `<xt>` - XML tag (dark cyan)
-- `<xa>` - XML attribute (purple)
-- `<xc>` - XML comment (medium blue)
-- `<xs>` - XML string (blue, italic)
-- `<xv>` - XML value (black)
-
-**JSON Code Tags**:
-- `<joc>` - JSON comment (green)
-- `<jok>` - JSON key (purple)
-- `<jov>` - JSON value (blue)
-
-**URL Encoding/UON Tags**:
-- `<ua>` - Attribute name (black)
-- `<uk>` - true/false/null (purple, bold)
-- `<un>` - Number value (dark blue)
-- `<us>` - String value (blue)
-
-**Manifest File Tags**:
-- `<mc>` - Manifest comment (green)
-- `<mk>` - Manifest key (dark red, bold)
-- `<mv>` - Manifest value (dark blue)
-- `<mi>` - Manifest import (dark blue, italic)
-
-**Config File Tags**:
-- `<cc>` - Config comment (green)
-- `<cs>` - Config section (dark red, bold)
-- `<ck>` - Config key (dark red)
-- `<cv>` - Config value (dark blue)
-- `<ci>` - Config import (dark red, bold, italic)
-
-**Special Tags**:
-- `<c>` - Synonym for `<code>`
-- `<dc>` - Deleted code (strikethrough)
-- `<bc>` - Bold code (bold)
-
-**Code Block Classes**:
-- `bcode` - Bordered code block
-- `bjava` - Bordered Java code block
-- `bjson` - Bordered JSON code block
-- `bxml` - Bordered XML code block
-- `bini` - Bordered INI code block
-- `buon` - Bordered UON code block
-- `burlenc` - Bordered URL encoding code block
-- `bconsole` - Bordered console output (black background, yellow text)
-- `bschema` - Bordered schema code block
-- `code` - Unbordered code block
-
-### Javadoc Structure
-
-**Standard Method Javadoc**:
-```java
-/**
- * Brief description of what the method does.
- *
- * <p>
- * Longer description if needed, explaining the purpose and behavior.
- * </p>
- *
- * @param paramName Description of the parameter.
- * @return Description of what is returned.
- * @throws ExceptionType Description of when this exception is thrown.
- */
-```
-
-**Property Documentation**:
-```java
-/**
- * The property name.
- *
- * @param value The new value for this property.
- * @return This object.
- */
-```
-
-### Parameter Documentation
-
-**Standard Parameters**:
-- Use `value` as the parameter name for fluent setters
-- Document parameter types and constraints
-- Specify when parameters can be null
-
-**Builder Method Parameter Naming**:
-- For single-value setter methods in builder classes, use `value` as the 
parameter name
-- This allows field assignment without the `this.` modifier (e.g., `field = 
value` instead of `this.field = value`)
-- Improves code readability and reduces redundancy
-
-**Null Parameter Handling**:
-```java
-/**
- * Sets the property value.
- *
- * @param value The new value. Can be <jk>null</jk> to unset the property.
- * @return This object.
- */
-```
-
-**Required Parameters**:
-```java
-/**
- * Sets the property value.
- *
- * @param value The new value. Must not be <jk>null</jk>.
- * @return This object.
- */
-```
-
-## Link and Reference Standards
-
-### Documentation Links
-
-**Juneau Documentation Site**:
-- Use hardcoded links to `https://juneau.apache.org/docs/topics/`
-- Use slug names as topic names
-- Use page titles for anchor text
-
-**Examples**:
-```java
-/**
- * <h5 class='section'>See Also:</h5><ul>
- *     <li class='link'><a class="doclink" 
href="https://juneau.apache.org/docs/topics/ModuleName";>module-name</a>
- * </ul>
- */
-```
-
-**External Specification Links**:
-```java
-/**
- * <a class="doclink" 
href="https://example.com/specification/#property";>property</a> description.
- */
-```
-
-### Cross-References
-
-**Internal Class References**:
-- Use `{@link ClassName}` for internal class references
-- Use `{@link ClassName#methodName}` for method references
-
-**External References**:
-- Use `<a class="doclink" href="URL">text</a>` for external links
-- Include specification links for external standards where applicable
-
-## Code Examples
-
-### JSON Serialization Examples
-
-**Standard Pattern**:
-```java
-/**
- * <jc>// Serialize using JsonSerializer.</jc>
- * String <jv>json</jv> = Json.<jsm>from</jsm>(<jv>x</jv>);
- *
- * <jc>// Or just use toString() which does the same as above.</jc>
- * String <jv>json</jv> = <jv>x</jv>.toString();
- */
-```
-
-**Consistency Requirements**:
-- Always include both `Json.from()` and `toString()` examples
-- Use consistent variable names (`<jv>json</jv>`, `<jv>x</jv>`)
-- Include explanatory comments
-
-### Method Usage Examples
-
-**Fluent Setter Examples**:
-```java
-/**
- * <jc>// Create a link element</jc>
- * A <jv>link</jv> = a().href("https://example.com";).target("_blank");
- */
-```
-
-**Builder Pattern Examples**:
-```java
-/**
- * <jc>// Create a Swagger document</jc>
- * Swagger <jv>swagger</jv> = swagger()
- *     .info(info().title("My API").version("1.0"))
- *     .path("/users", pathItem().get(operation().summary("Get users")));
- */
-```
-
-## Property Documentation
-
-### Bean Properties
-
-**Standard Property Documentation**:
-```java
-/**
- * The property description.
- *
- * @param value The new value for this property.
- * @return This object.
- */
-```
-
-**Property with External Link Documentation**:
-```java
-/**
- * The <a class="doclink" 
href="https://example.com/spec#property";>property</a> description.
- *
- * @param value A description of the parameter.
- * @return This object.
- */
-```
-
-## Class Documentation
-
-### Class-Level Javadoc
-
-**Standard Structure**:
-```java
-/**
- * Brief description of the class purpose.
- *
- * <h5 class='section'>See Also:</h5><ul>
- *     <li class='link'><a class="doclink" 
href="https://juneau.apache.org/docs/topics/ModuleName";>module-name</a>
- * </ul>
- */
-```
-
-**Builder Classes**:
-```java
-/**
- * Builder class for creating {@link ClassName} objects.
- *
- * <p>
- * This class provides fluent methods for building complex objects.
- * </p>
- */
-```
-
-## Validation and Error Documentation
-
-### Parameter Validation
-
-**Null Parameter Validation**:
-```java
-/**
- * Sets the property value.
- *
- * @param value The new value. Must not be <jk>null</jk>.
- * @throws IllegalArgumentException If value is <jk>null</jk>.
- * @return This object.
- */
-```
-
-**String Validation**:
-```java
-/**
- * Sets the property value.
- *
- * @param value The new value. Must not be <jk>null</jk> or blank.
- * @throws IllegalArgumentException If value is <jk>null</jk> or blank.
- * @return This object.
- */
-```
-
-### Strict Mode Documentation
-
-**Strict Mode Behavior**:
-```java
-/**
- * Sets the property value.
- *
- * <p>
- * In strict mode, invalid values will throw {@link RuntimeException}.
- * In non-strict mode, invalid values are ignored.
- * </p>
- *
- * @param value The new value.
- * @return This object.
- */
-```
-
-## Special Cases
-
-### Constructor Documentation
-
-**Standard Constructor**:
-```java
-/**
- * Constructor.
- *
- * @param children The child nodes.
- */
-public ClassName(Object...children) {
-```
-
-**Parameterized Constructor**:
-```java
-/**
- * Constructor.
- *
- * @param param1 Description of first parameter.
- * @param param2 Description of second parameter.
- */
-public ClassName(Type1 param1, Type2 param2) {
-```
-
-### Override Documentation
-
-**Method Overrides**:
-```java
-@Override /* <SimpleClassName> */
-public ClassName methodName(Type value) {
-```
-
-**Interface Implementations**:
-```java
-@Override /* <SimpleClassName> */
-public ClassName methodName(Type value) {
-```
-
-## Best Practices
-
-### Consistency
-- Use consistent parameter names (`value` for fluent setters)
-- Use consistent variable names in examples
-- Use consistent link formatting
-
-### Completeness
-- Document all public methods and constructors
-- Include parameter types and constraints
-- Include return value descriptions
-- Include exception documentation
-
-### Clarity
-- Use clear, concise descriptions
-- Include practical examples
-- Link to relevant specifications
-- Explain complex behavior
-
-### Maintenance
-- Keep documentation up-to-date with code changes
-- Use consistent formatting throughout
-- Include cross-references where helpful
-- Document edge cases and special behavior
-
-## Common Patterns
-
-### Fluent Setter Documentation
-```java
-/**
- * Sets the property value.
- *
- * @param value The new value for this property.
- * @return This object.
- */
-public ClassName property(Type value) {
-```
-
-### Collection Setter Documentation
-```java
-/**
- * Sets the collection of items.
- *
- * @param value The new collection. Can be <jk>null</jk> to unset the property.
- * @return This object.
- */
-public ClassName items(Collection<Item> value) {
-```
-
-### Builder Method Documentation
-```java
-/**
- * Creates a new instance.
- *
- * @return A new instance.
- */
-public static ClassName create() {
-```
-
-This document serves as the definitive guide for documentation in the Apache 
Juneau project, ensuring consistency, completeness, and clarity across all 
documentation.
-
----
-
-# Unit Testing Guidelines for Apache Juneau
-
-This document outlines the testing conventions, methodologies, and best 
practices for unit testing in the Apache Juneau project.
-
-## Core Testing Conventions
-
-### Sequential Single-Letter Label Convention (SSLLC)
-
-**Purpose**: Provides consistent, readable naming for test data that improves 
test maintainability and readability.
-
-**Rules**:
-1. **Single values**: Use single letters (`a`, `b`, `c`, etc.)
-2. **Multiple values on same line**: Append numbers (`a1`, `a2`, `b1`, `b2`, 
etc.)
-3. **New bean instances**: Reset labels to 'a' when creating new bean instances
-4. **Consistent prefixes**: Use consistent prefixes for multiple values on the 
same line
-
-**Examples**:
-```java
-// Single values
-var a = swagger();
-var b = info();
-
-// Multiple values on same line
-var a1 = operation("get", "/users");
-var a2 = operation("post", "/users");
-var b1 = response("200");
-var b2 = response("400");
-
-// New bean instance - reset to 'a'
-var a = new Swagger();
-var b = a.info();
-```
-
-### Deep Property Path Assertion Pattern (DPPAP)
-
-**Purpose**: Assert on actual nested property values using deep property paths 
rather than just collection sizes.
-
-**Usage**: Use `assertBean()` with deep property paths to verify actual 
values, not just collection sizes.
-
-**Examples**:
-```java
-// Instead of just checking size
-assertNotNull(swagger.getPaths());
-assertEquals(2, swagger.getPaths().size());
-
-// Use deep property path assertions
-assertBean(swagger, 
"paths{get:/users{summary,operationId},post:/users{summary,operationId}}");
-```
-
-### TestUtils Convenience Methods
-
-**Purpose**: Use TestUtils methods instead of direct serializer/parser calls 
for consistency and readability.
-
-**Methods**:
-- `TestUtils.json(Object)` - Serialize object to JSON string
-- `TestUtils.json(String, Class)` - Deserialize JSON string to object
-- `TestUtils.jsonRoundTrip(Object, Class)` - Round-trip 
serialization/deserialization testing
-
-**Examples**:
-```java
-// Instead of direct serializer calls
-String json = Json5Serializer.DEFAULT.toString(swagger);
-Swagger parsed = Json5Parser.DEFAULT.parse(json, Swagger.class);
-
-// Use TestUtils convenience methods
-String json = json(swagger);
-Swagger parsed = json(json, Swagger.class);
-Swagger roundTrip = jsonRoundTrip(swagger, Swagger.class);
-```
-
-## Test Structure Patterns
-
-### Test Class Naming Convention
-
-All test methods follow the pattern: `LNN_testName` where:
-- **L** is a letter from 'a'-'z' representing the test category
-- **NN** is a number from "00"-"99" for ordering tests within a category
-- **testName** is a descriptive name for what the test does
-
-**Examples:**
-- `a01_basicTest()` - First test in category 'a'
-- `b05_serializationTest()` - Fifth test in category 'b'
-- `c12_validationTest()` - Twelfth test in category 'c'
-
-### Simple Test Class Structure
-
-For test classes with a small number of tests:
-
-```java
-public class BeanName_Test extends TestBase {
-    
-    @Test void a01_basicPropertyTest() {
-        // Test basic properties
-    }
-    
-    @Test void a02_fluentSetters() {
-        // Test fluent setter methods
-    }
-    
-    @Test void b01_serialization() {
-        // Test JSON serialization
-    }
-    
-    @Test void b02_deserialization() {
-        // Test JSON deserialization
-    }
-}
-```
-
-**Key Points:**
-- Tests are grouped by letter prefix (a, b, c, etc.)
-- Each group represents a general test category
-- Tests within a group are numbered sequentially
-
-### Complex Test Class Structure
-
-For test classes with large numbers of tests that can be grouped into major 
categories:
-
-```java
-public class BeanName_Test extends TestBase {
-    
-    @Nested class A_basicTests extends TestBase {
-        @Test void a01_properties() {
-            // Test bean properties using varargs setters
-            // Use SSLLC naming convention
-            // Use DPPAP for assertions
-        }
-        
-        @Test void a02_fluentSetters() {
-            // Test fluent setter chaining
-        }
-    }
-    
-    @Nested class B_serialization extends TestBase {
-        @Test void b01_toJson() {
-            // Test JSON serialization
-            // Use TestUtils convenience methods
-        }
-        
-        @Test void b02_fromJson() {
-            // Test JSON deserialization
-        }
-    }
-    
-    @Nested class C_extraProperties extends TestBase {
-        @Test void c01_dynamicProperties() {
-            // Test set(String, Object) method
-            // Use set(String, Object) for ALL the same properties as 
A_basicTests
-            // Match values from A_basicTests exactly
-        }
-    }
-    
-    @Nested class D_additionalMethods extends TestBase {
-        @Test void d01_collectionSetters() {
-            // Test setX(Collection<X>) methods
-        }
-        
-        @Test void d02_varargAdders() {
-            // Test addX(X...) methods
-        }
-    }
-}
-```
-
-**Key Points:**
-- Use `@Nested` inner classes for major test categories
-- Each nested class name follows the pattern: `L_categoryName` where L is an 
uppercase letter (A, B, C, etc.)
-- Tests within nested classes use `l##_testName` pattern where l is the 
lowercase letter matching the nested class (a, b, c, etc.) and ## is an 
incrementing number (01, 02, 03, etc.)
-- The letter in the nested class name matches the letter in the test method 
names (uppercase for class, lowercase for methods)
-- Each nested class extends `TestBase` to inherit test utilities and setup
-
-### Common Test Categories
-
-While not prescriptive, common test category prefixes include:
-- **a**: Basic tests (properties, constructors, basic functionality)
-- **b**: Serialization/deserialization tests
-- **c**: Extra/dynamic properties tests
-- **d**: Additional methods tests
-- **e**: Validation/strict mode tests
-- **f**: Reference resolution tests (where applicable)
-
-Choose the structure (Simple vs Complex) based on:
-- **Simple**: < 20 tests, or tests don't naturally group into major categories
-- **Complex**: > 20 tests, especially when tests group into distinct 
functional areas
-
-## Assertion Patterns
-
-### assertBean Usage
-
-**Basic Usage**:
-```java
-assertBean(bean, "property1,property2,property3");
-```
-
-**Deep Property Paths**:
-```java
-assertBean(bean, "paths{get:/users{summary,operationId}}");
-```
-
-**Collection Assertions**:
-```java
-// Use # notation for uniform collections
-assertBean(bean, "parameters{#{in,name}}");
-
-// Use explicit indexing for non-uniform collections
-assertBean(bean, "parameters{0{in,name},1{in,name}}");
-```
-
-**Map Assertions**:
-```java
-// Use assertMap for map entries
-assertMap(map, "key1=value1", "key2=value2");
-```
-
-### Exception Testing
-
-**Use assertThrowsWithMessage**:
-```java
-assertThrowsWithMessage(IllegalArgumentException.class, 
-    "Parameter 'name' cannot be null", 
-    () -> bean.setName(null));
-```
-
-## Bean Testing Patterns
-
-### General Bean Testing
-
-**Property Coverage**: Ensure `A_basicTests` covers all bean properties and 
`C_extraProperties` covers the same properties using the `set()` method.
-
-**Getter/Setter Variants**: Test both collection variants and varargs variants 
where applicable.
-
-### Fluent Setter Testing
-
-**Parameter Naming**: All fluent setters should use `value` as the parameter 
name for consistency.
-
-**Method Chaining**: Test fluent setter chaining:
-```java
-var result = bean
-    .property1("value1")
-    .property2("value2")
-    .property3("value3");
-```
-
-### Collection Property Method Consistency
-
-**Rule**: All collection bean properties should have exactly 4 methods:
-1. `setX(X...)` - varargs setter
-2. `setX(Collection<X>)` - Collection setter  
-3. `addX(X...)` - varargs adder
-4. `addX(Collection<X>)` - Collection adder
-
-**Examples**:
-```java
-// For a tags property of type Set<String>:
-public Bean setTags(String...value) { ... }
-public Bean setTags(Collection<String> value) { ... }
-public Bean addTags(String...values) { ... }
-public Bean addTags(Collection<String> values) { ... }
-```
-
-### Varargs vs Collection Setter Testing
-
-**Rule**: When a bean has both varargs and Collection setter methods for the 
same property:
-- **A_basicTests**: Use the varargs version (e.g., `setTags("tag1", "tag2")`)
-- **D_additionalMethods**: Test the Collection version (e.g., 
`setTags(list("tag1", "tag2"))`)
-
-**Examples**:
-```java
-// A_basicTests - use varargs
-.setTags("tag1", "tag2")
-.setConsumes(MediaType.of("application/json"))
-
-// D_additionalMethods - test Collection version
-.setTags(list("tag1", "tag2"))
-.setConsumes(list(MediaType.of("application/json"), 
MediaType.of("application/xml")))
-```
-
-**D_additionalMethods Test Structure**: This test class should contain three 
tests:
-
-1. **d01_collectionSetters**: Tests `setX(Collection<X>)` methods
-   ```java
-   @Test void d01_collectionSetters() {
-       var x = bean()
-           .setTags(list("tag1", "tag2"))
-           .setConsumes(list(MediaType.of("application/json"), 
MediaType.of("application/xml")));
-       
-       assertBean(x,
-           "tags,consumes",
-           "[tag1,tag2],[application/json,application/xml]"
-       );
-   }
-   ```
-
-2. **d02_varargAdders**: Tests `addX(X...)` methods - each method should be 
called twice
-   ```java
-   @Test void d02_varargAdders() {
-       var x = bean()
-           .addTags("tag1")
-           .addTags("tag2")
-           .addConsumes(MediaType.of("application/json"))
-           .addConsumes(MediaType.of("application/xml"));
-       
-       assertBean(x,
-           "tags,consumes",
-           "[tag1,tag2],[application/json,application/xml]"
-       );
-   }
-   ```
-
-3. **d03_collectionAdders**: Tests `addX(Collection<X>)` methods - each method 
should be called twice
-   ```java
-   @Test void d03_collectionAdders() {
-       // Note: Collection versions of addX methods exist but are difficult to 
test
-       // due to Java method resolution preferring varargs over Collection
-       // For now, we test the basic functionality with varargs versions
-       var x = bean();
-       
-       // Test that the addX methods work by calling them multiple times
-       x.addTags("tag1");
-       x.addTags("tag2");
-       x.addConsumes(MediaType.of("application/json"));
-       x.addConsumes(MediaType.of("application/xml"));
-       
-       assertBean(x,
-           "tags,consumes",
-           "[tag1,tag2],[application/json,application/xml]"
-       );
-   }
-   ```
-
-In all cases, `assertBean` should be used to validate results.
-
-## Code Coverage Guidelines
-
-### Target Coverage
-- **Bean Classes**: Aim for 100% instruction coverage
-- **UI Classes**: Can be excluded from coverage targets
-- **Builder Classes**: Include comprehensive tests for all builder methods
-
-### Coverage Analysis
-- Use `coverage.py` to identify missing coverage — always run it after writing 
unit tests for new code:
-  ```bash
-  ./scripts/coverage.py path/to/NewFile.java --run
-  ./scripts/coverage.py path/to/new/package/ --run
-  ./scripts/coverage.py path/to/new/package/ --branches
-  ```
-- Focus on methods with 0% coverage first
-- Add tests for uncovered code paths
-- Verify coverage improvements after adding tests
-
-## Best Practices
-
-### Test Data Management
-- Use SSLLC for consistent test data naming
-- Reset labels when creating new bean instances
-- Use meaningful test data that represents real-world scenarios
-
-### Assertion Strategy
-- Prefer `assertBean()` over individual property assertions
-- Use deep property paths for comprehensive validation
-- Test both positive and negative scenarios
-
-### Code Organization
-- Group related tests in logical test methods
-- Use descriptive test method names
-- Follow consistent test structure across all test classes
-
-### Test Helper Class Naming Convention
-
-**Rule**: For test helper classes that are only used by one test, prefix the 
class name with the test method prefix and move it immediately above the test 
that uses it.
-
-**Naming Pattern**: `LNN_ClassName` where:
-- **L** is the uppercase letter matching the test method prefix (A, B, C, etc.)
-- **NN** is the two-digit number matching the test method number (01, 02, 03, 
etc.)
-- **ClassName** is the descriptive class name
-
-**Placement**: Move the helper class definition to immediately above the test 
method that uses it.
-
-**Examples**:
-```java
-// WRONG - Generic name, defined far from usage
-public static class BeanWithDeprecatedGetInstance {
-    // ...
-}
-
-@Test
-void c03_createBeanIgnoresDeprecatedGetInstance() {
-    var bean = bc(BeanWithDeprecatedGetInstance.class).run();
-    // ...
-}
-
-// CORRECT - Prefixed with test name, placed above test
-@Test
-void c03_createBeanIgnoresDeprecatedGetInstance() {
-    // Bean with both deprecated and valid getInstance methods
-    public static class C03_BeanWithDeprecatedGetInstance {
-        private static final C03_BeanWithDeprecatedGetInstance INSTANCE = new 
C03_BeanWithDeprecatedGetInstance();
-        // ...
-    }
-
-    var bean = bc(C03_BeanWithDeprecatedGetInstance.class).run();
-    // ...
-}
-```
-
-**Rationale**:
-- Makes it immediately clear which test uses the helper class
-- Reduces namespace pollution by scoping helper classes to their tests
-- Improves code locality by keeping related code together
-- Makes it easier to identify unused helper classes
-
-**When to Apply**:
-- Only apply this convention to helper classes used by a single test
-- Classes used by multiple tests should keep their generic names
-- Classes used across nested test classes should remain at the nested class 
level
-
-### Test State Capture Utilities
-
-**Purpose**: Use proper utility classes instead of arrays for capturing 
mutable state in lambdas and test scenarios.
-
-**Rules**:
-1. **Use `Flag` for boolean state**: Instead of `new boolean[]{false}`, use 
`Flag.create()` for capturing boolean flags in lambdas and test hooks.
-2. **Use `IntegerValue` for integer counters**: Instead of `new int[]{0}`, use 
`IntegerValue.create()` for capturing integer counts in lambdas and test hooks.
-
-**Examples**:
-```java
-// WRONG - Using arrays for state capture
-var hookCalled = new boolean[]{false};
-bc(SimpleBean.class)
-    .postCreateHook(b -> hookCalled[0] = true)
-    .run();
-assertTrue(hookCalled[0]);
-
-var callCount = new int[]{0};
-bc(SimpleBean.class)
-    .postCreateHook(b -> callCount[0]++)
-    .run();
-assertEquals(1, callCount[0]);
-
-// CORRECT - Using Flag and IntegerValue
-var hookCalled = Flag.create();
-bc(SimpleBean.class)
-    .postCreateHook(b -> hookCalled.set())
-    .run();
-assertTrue(hookCalled.isSet());
-
-var callCount = IntegerValue.create();
-bc(SimpleBean.class)
-    .postCreateHook(b -> callCount.increment())
-    .run();
-assertEquals(1, callCount.get());
-```
-
-**Flag Methods**:
-- `Flag.create()` - Creates a flag initialized to `false`
-- `flag.set()` - Sets the flag to `true`
-- `flag.isSet()` - Returns `true` if flag is set
-- `flag.isUnset()` - Returns `true` if flag is not set
-- `flag.setIf(condition)` - Sets flag if condition is `true`
-
-**IntegerValue Methods**:
-- `IntegerValue.create()` - Creates an integer initialized to `0`
-- `counter.increment()` - Increments by 1
-- `counter.get()` - Returns the current value
-- `counter.getAndIncrement()` - Returns current value then increments
-- `counter.incrementAndGet()` - Increments then returns new value
-
-**Rationale**:
-- Provides cleaner, more readable code than array access patterns
-- Better type safety and API design
-- Consistent with Apache Juneau utility class patterns
-- Makes test code more maintainable and easier to understand
-
-### Documentation
-- Include javadoc for test methods explaining their purpose
-- Document any special test scenarios or edge cases
-- Keep test code readable and maintainable
-
-## Common Patterns
-
-### Round-trip Testing
-```java
-@Test void B_serialization() {
-    var original = createTestBean();
-    var roundTrip = jsonRoundTrip(original, BeanClass.class);
-    assertBean(original, roundTrip);
-}
-```
-
-### Strict Mode Testing
-```java
-@Test void E_strictMode() {
-    // Test invalid value with strict mode
-    assertThrowsWithMessage(RuntimeException.class, 
-        "Invalid value", 
-        () -> bean.setProperty("invalid"));
-    
-    // Test valid value with strict mode
-    assertDoesNotThrow(() -> bean.setProperty("valid"));
-}
-```
-
-### Collection Testing
-```java
-@Test void a08_otherGettersAndSetters() {
-    var a = bean.addItems("item1", "item2");
-    assertBean(a, "items{0=item1,1=item2}");
-    
-    var b = bean.setItems(Arrays.asList("item3", "item4"));
-    assertBean(b, "items{0=item3,1=item4}");
-}
-```
-
-## Serializer and Parser Implementation Rules
-
-### Adding Settings to Serializers/Parsers
-
-When adding a new setting (configuration property) to a serializer or parser, 
follow these steps:
-
-#### 1. Add Field to Builder Class
-```java
-public static class Builder extends XmlSerializer.Builder {
-    String textNodeDelimiter;  // Add the field
-}
-```
-
-#### 2. Initialize in Constructor
-```java
-protected Builder() {
-    textNodeDelimiter = env("XmlSerializer.textNodeDelimiter", "");  // Set 
default
-}
-```
-
-#### 3. Add to Copy Constructors
-```java
-protected Builder(XmlSerializer copyFrom) {
-    super(copyFrom);
-    textNodeDelimiter = copyFrom.textNodeDelimiter;  // Copy from serializer
-}
-
-protected Builder(Builder copyFrom) {
-    super(copyFrom);
-    textNodeDelimiter = copyFrom.textNodeDelimiter;  // Copy from builder
-}
-```
-
-#### 4. Add Setter Method
-```java
-public Builder textNodeDelimiter(String value) {
-    textNodeDelimiter = value == null ? "" : value;
-    return this;
-}
-```
-
-#### 5. **CRITICAL: Update hashKey() Method**
-This is essential to prevent caching issues where different configurations 
would incorrectly share the same cached instance:
-
-```java
-@Override /* Context.Builder */
-public HashKey hashKey() {
-    return HashKey.of(
-        super.hashKey(),
-        addBeanTypesXml,
-        addNamespaceUrisToRoot,
-        // ... other fields ...
-        textNodeDelimiter  // ADD NEW SETTING HERE
-    );
-}
-```
-
-**Why this is critical**: Serializers and parsers use caching based on the 
hash key. If a new setting is not included in the hash key, two builders with 
different values for that setting will hash to the same key and incorrectly use 
the same cached instance, causing the second configuration to be ignored.
-
-#### 6. Add Field to Main Class
-```java
-public class XmlSerializer extends WriterSerializer {
-    final String textNodeDelimiter;  // Add to main class
-    
-    public XmlSerializer(Builder builder) {
-        super(builder);
-        textNodeDelimiter = builder.textNodeDelimiter;  // Initialize from 
builder
-    }
-}
-```
-
-#### 7. Pass to Session (if needed)
-If the setting needs to be accessed during serialization:
-
-```java
-public class XmlSerializerSession extends WriterSerializerSession {
-    private final String textNodeDelimiter;
-    
-    protected XmlSerializerSession(Builder builder) {
-        super(builder);
-        textNodeDelimiter = ctx.textNodeDelimiter;  // Get from context
-    }
-}
-```
-
-#### 8. Override in Subclasses (if needed)
-If the serializer has subclasses (e.g., `HtmlSerializer` extends 
`XmlSerializer`), override the setter to maintain fluent API:
-
-```java
-// In HtmlSerializer.Builder
-@Override
-public Builder textNodeDelimiter(String value) {
-    super.textNodeDelimiter(value);  // Call parent
-    return this;  // Return correct type
-}
-```
-
-### Common Pitfalls
-- ❌ **Forgetting to add the setting to `hashKey()`** - This causes caching 
bugs where different configurations share the same cached instance
-- ❌ Not copying the field in all copy constructors
-- ❌ Not overriding setter methods in subclass builders
-- ❌ Not passing the setting to the session if it's needed during serialization
-
-This document serves as the definitive guide for unit testing in the Apache 
Juneau project, ensuring consistency, maintainability, and comprehensive test 
coverage.
-
----
-
-## Release Notes Guidelines
-
-### Location
-When asked to "add to the release notes", this refers to the current release 
file located at:
-- `/docs/pages/release-notes/<VERSION>.md`
-- **Current version**: `9.2.1`
-- **Current file**: `/docs/pages/release-notes/9.2.1.md`
-
-### Structure
-Release notes are organized into two main sections:
-
-1. **Top-level major changes** - High-level overview at the beginning of the 
file listing significant changes
-2. **Per-module updates** - Detailed changes organized by module (similar to 
9.0.0.md structure):
-   - `juneau-marshall`
-   - `juneau-rest-common`
-   - `juneau-rest-server`
-   - `juneau-rest-client`
-   - `juneau-dto`
-   - `juneau-microservice`
-   - `juneau-examples`
-   - Other modules as applicable
-
-### Format
-Each section should include:
-- New features
-- Bug fixes
-- Breaking changes
-- Deprecations
-- Performance improvements
-- Documentation updates
-- API changes
-
-### Process
-1. Read the current release notes file (9.2.0.md) to understand the existing 
structure
-2. Determine if the change is a major change (top-level) or module-specific
-3. Add new entries under the appropriate section and module
-4. Use clear, concise descriptions with code examples where helpful
-5. Include issue/PR references where applicable
-6. Maintain consistent formatting with existing entries (see 9.0.0.md for 
reference)

Reply via email to