Skip to content

Commit 09eb00d

Browse files
fix: harden eval integrity and release safety
1 parent 78b96f8 commit 09eb00d

134 files changed

Lines changed: 1724 additions & 926 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/ISSUE_TEMPLATE/bug_report.yml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ body:
2424
- Skill behavior
2525
- README or docs
2626
- Evals or scoring
27-
- Tessl install or tile metadata
27+
- Tessl install or plugin metadata
2828
- Tessl publish or registry display
2929
- CI, release, or dependency automation
3030
- Not sure
@@ -78,17 +78,17 @@ body:
7878
description: Paste sanitized command output, eval output, CI links, or Tessl output if useful.
7979
render: text
8080
- type: input
81-
id: tile-version
81+
id: plugin-version
8282
attributes:
83-
label: Tessl tile version
84-
description: Paste the published tile version, `tessl` output, or the commit SHA if known.
83+
label: Tessl plugin version
84+
description: Paste the published plugin version, `tessl` output, or the commit SHA if known.
8585
placeholder: "martinfrancois/java-optionals version or commit SHA: "
8686
- type: input
8787
id: model
8888
attributes:
8989
label: Model
9090
description: For agent-output bugs, name the model that produced the behavior.
91-
placeholder: "For example: Claude Opus 4.8 or GPT-5.5"
91+
placeholder: "For example: model name and version"
9292
- type: dropdown
9393
id: reasoning-effort
9494
attributes:

.github/ISSUE_TEMPLATE/feature_request.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ body:
1919
- Optional example or reference material
2020
- Evals or scoring
2121
- README or docs
22-
- Tessl install or tile metadata
22+
- Tessl install or plugin metadata
2323
- CI, release, or dependency automation
2424
- Other
2525
validations:

.github/pull_request_template.md

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,14 +46,17 @@ Checks most contributors can run:
4646

4747
- [ ] `python3 scripts/validate_skill.py skills/java-optionals`
4848
- [ ] `python3 scripts/validate_eval_criteria.py evals evals-reference`
49+
- [ ] `python3 -m py_compile scripts/validate_skill.py scripts/validate_eval_criteria.py`
50+
- [ ] `bash -n scripts/check_publish_dry_run.sh`
4951
- [ ] `tessl plugin lint .`
5052
- [ ] `markdownlint`, if Markdown changed
5153
- [ ] Manual rendered-doc or example review, if docs or examples changed
5254

5355
Tessl-authenticated checks:
5456

5557
- [ ] `bash scripts/check_publish_dry_run.sh .`
56-
- [ ] `tessl skill review --threshold 100 skills/java-optionals/SKILL.md`, if skill text or references changed
58+
- [ ] `tessl plugin publish --dry-run --bump patch .`
59+
- [ ] `tessl skill review --threshold 90 skills/java-optionals/SKILL.md`, if skill text or references changed
5760
- [ ] `tessl eval run --variant with-context --variant without-context .`, if skill behavior,
5861
evals, or benchmark claims changed
5962

@@ -80,6 +83,22 @@ explain why.
8083

8184
- [ ] Docs updated, or N/A
8285
- [ ] Evals updated, or N/A
86+
- [ ] Scenario directories include `task.md`, `criteria.json`, and `capability.txt`, or N/A
87+
- [ ] Scenario invocation style is classified as natural or explicit, or N/A
88+
- [ ] Natural activation prompts don't explicitly invoke the skill, or N/A
89+
- [ ] Explicit invocation prompts are labeled as explicit, or N/A
90+
- [ ] Headline criteria include compile/artifact checks, or N/A
91+
- [ ] Headline criteria include behavior correctness checks, or N/A
92+
- [ ] Runtime references contain no eval answer keys, scenario inventory, hosted run IDs, or fixed
93+
score claims
94+
- [ ] Java baseline compatibility has been considered, or N/A
95+
- [ ] `OptionalInt`, `OptionalLong`, and `OptionalDouble` guidance has been considered, or N/A
96+
- [ ] Optional-producing stream terminals and collectors are covered, or N/A
97+
- [ ] Java 26 Javadocs were checked for Optional-family coverage, or N/A
98+
- [ ] Valid README package-runner instructions were preserved, or N/A
99+
- [ ] Tessl package commands match the verified plugin package format
100+
- [ ] Full/reference eval reporting is not hidden or cherry-picked
101+
- [ ] Tessl checks were run, or unavailability is documented
83102
- [ ] PR title or squash title uses Conventional Commits
84103
- [ ] Redaction checked: no Tessl tokens, GitHub tokens, package manager tokens, private repository
85104
links, private eval artifacts, private registry/workspace links, local host paths, or

.github/workflows/ci.yml

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ jobs:
2828
- name: Setup Tessl CLI
2929
uses: tesslio/setup-tessl@25ec223fc0da33b41b8044ff5ab2b85235f4f91e # v2
3030
with:
31-
version: "0.81.1"
31+
version: "0.81.2"
3232
token: ${{ env.TESSL_TOKEN }}
3333

3434
- name: Validate skill metadata
@@ -37,13 +37,47 @@ jobs:
3737
- name: Validate eval criteria
3838
run: python3 scripts/validate_eval_criteria.py evals evals-reference
3939

40+
- name: Compile validation scripts
41+
run: python3 -m py_compile scripts/validate_skill.py scripts/validate_eval_criteria.py
42+
43+
- name: Check shell scripts
44+
run: bash -n scripts/check_publish_dry_run.sh
45+
46+
- name: Parse JSON files
47+
run: |
48+
python3 - <<'PY'
49+
import json
50+
import pathlib
51+
for path in pathlib.Path('.').rglob('*.json'):
52+
json.load(open(path, encoding='utf-8'))
53+
print('JSON ok')
54+
PY
55+
56+
- name: Parse YAML files
57+
run: |
58+
python3 - <<'PY'
59+
import pathlib
60+
try:
61+
import yaml
62+
except ImportError:
63+
print('PyYAML unavailable; skipping YAML parse')
64+
raise SystemExit(0)
65+
for path in list(pathlib.Path('.').rglob('*.yml')) + list(pathlib.Path('.').rglob('*.yaml')):
66+
yaml.safe_load(open(path, encoding='utf-8'))
67+
print('YAML ok')
68+
PY
69+
4070
- name: Lint Tessl plugin
4171
run: tessl plugin lint .
4272

43-
- name: Check publish dry-run
73+
- name: Check fast publish dry-run
4474
if: ${{ env.TESSL_TOKEN != '' }}
4575
run: bash scripts/check_publish_dry_run.sh .
4676

77+
- name: Check eval publish dry-run
78+
if: ${{ env.TESSL_TOKEN != '' }}
79+
run: tessl plugin publish --dry-run --bump patch .
80+
4781
- name: Skip publish dry-run when Tessl token is unavailable
4882
if: ${{ env.TESSL_TOKEN == '' }}
49-
run: echo "TESSL_TOKEN isn't configured; skipping publish dry-run."
83+
run: echo "TESSL_TOKEN isn't configured; skipping Tessl publish dry-runs."

.github/workflows/commitlint.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ permissions:
2222
pull-requests: read
2323

2424
concurrency:
25-
group: commitlint-${{ github.workflow }}-${{ github.event.pull_request.number }}
25+
group: commitlint-${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
2626
cancel-in-progress: true
2727

2828
jobs:
@@ -33,7 +33,7 @@ jobs:
3333
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
3434
with:
3535
fetch-depth: 0
36-
ref: ${{ github.event.pull_request.head.sha }}
36+
ref: ${{ github.event.pull_request.head.sha || github.sha }}
3737

3838
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
3939
with:

.github/workflows/publish-tessl.yml

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ permissions:
99
contents: read
1010

1111
concurrency:
12-
group: publish-tessl-${{ github.event.release.tag_name }}
12+
group: publish-tessl-${{ github.event.release.tag_name || github.run_id }}
1313
cancel-in-progress: false
1414

1515
jobs:
@@ -21,11 +21,27 @@ jobs:
2121
steps:
2222
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
2323

24+
- name: Require Tessl token
25+
run: |
26+
if [ -z "${TESSL_TOKEN:-}" ]; then
27+
echo "TESSL_TOKEN is required to publish the Tessl plugin." >&2
28+
exit 1
29+
fi
30+
2431
- name: Setup Tessl CLI
2532
uses: tesslio/setup-tessl@25ec223fc0da33b41b8044ff5ab2b85235f4f91e # v2
2633
with:
27-
version: "0.81.1"
34+
version: "0.81.2"
2835
token: ${{ env.TESSL_TOKEN }}
2936

37+
- name: Validate plugin before publish
38+
run: |
39+
python3 scripts/validate_skill.py skills/java-optionals
40+
python3 scripts/validate_eval_criteria.py evals evals-reference
41+
python3 -m py_compile scripts/validate_skill.py scripts/validate_eval_criteria.py
42+
bash -n scripts/check_publish_dry_run.sh
43+
tessl plugin lint .
44+
tessl plugin publish --dry-run .
45+
3046
- name: Publish plugin
3147
run: tessl plugin publish .

.github/workflows/release-please.yml

Lines changed: 4 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -27,20 +27,6 @@ jobs:
2727
config-file: release-please-config.json
2828
manifest-file: .release-please-manifest.json
2929

30-
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
31-
if: ${{ steps.release.outputs.release_created == 'true' }}
32-
33-
- name: Setup Tessl CLI for release publish
34-
if: ${{ steps.release.outputs.release_created == 'true' }}
35-
uses: tesslio/setup-tessl@25ec223fc0da33b41b8044ff5ab2b85235f4f91e # v2
36-
with:
37-
version: "0.81.1"
38-
token: ${{ secrets.TESSL_TOKEN }}
39-
40-
- name: Publish Tessl plugin
41-
if: ${{ steps.release.outputs.release_created == 'true' }}
42-
run: tessl plugin publish .
43-
4430
- name: Find release PR
4531
id: release-pr
4632
env:
@@ -78,7 +64,7 @@ jobs:
7864
if: ${{ steps.release-pr.outputs.found == 'true' }}
7965
uses: tesslio/setup-tessl@25ec223fc0da33b41b8044ff5ab2b85235f4f91e # v2
8066
with:
81-
version: "0.81.1"
67+
version: "0.81.2"
8268
token: ${{ secrets.TESSL_TOKEN }}
8369

8470
- name: Validate release PR
@@ -109,10 +95,13 @@ jobs:
10995
11096
python3 scripts/validate_skill.py skills/java-optionals
11197
python3 scripts/validate_eval_criteria.py evals evals-reference
98+
python3 -m py_compile scripts/validate_skill.py scripts/validate_eval_criteria.py
99+
bash -n scripts/check_publish_dry_run.sh
112100
tessl plugin lint .
113101
114102
if [ -n "${TESSL_TOKEN:-}" ]; then
115103
bash scripts/check_publish_dry_run.sh .
104+
tessl plugin publish --dry-run .
116105
else
117106
echo "TESSL_TOKEN isn't configured; skipping publish dry-run."
118107
fi

.github/workflows/skill-review.yml

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,13 @@ on:
99
- main
1010
paths:
1111
- ".github/workflows/skill-review.yml"
12-
- "skills/java-optionals/SKILL.md"
13-
- "skills/java-optionals/references/**"
12+
- ".tessl-plugin/plugin.json"
13+
- "tile.json"
14+
- "tessl.json"
15+
- "README.md"
16+
- "CONTRIBUTING.md"
17+
- "docs/agents/**"
18+
- "skills/java-optionals/**"
1419

1520
concurrency:
1621
group: skill-review-${{ github.workflow }}-${{ github.ref }}
@@ -33,9 +38,9 @@ jobs:
3338
if: ${{ env.TESSL_TOKEN != '' }}
3439
uses: tesslio/setup-tessl@25ec223fc0da33b41b8044ff5ab2b85235f4f91e # v2
3540
with:
36-
version: "0.81.1"
41+
version: "0.81.2"
3742
token: ${{ env.TESSL_TOKEN }}
3843

3944
- name: Review skill
4045
if: ${{ env.TESSL_TOKEN != '' }}
41-
run: tessl skill review --threshold 100 skills/java-optionals/SKILL.md
46+
run: tessl skill review --threshold 90 skills/java-optionals/SKILL.md

.tessl-plugin/plugin.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@
33
"version": "0.1.24",
44
"description": "Help AI coding agents use Java Optional well in new code and cleanups, without replacing one antipattern with another.",
55
"summary": "Help AI coding agents use Java Optional well in new code and cleanups, without replacing one antipattern with another.",
6+
"repository": "https://github.com/martinfrancois/java-optionals-skill",
7+
"homepage": "https://github.com/martinfrancois/java-optionals-skill#readme",
8+
"license": "MIT",
69
"entrypoint": "README.md",
710
"private": false
811
}

CONTRIBUTING.md

Lines changed: 40 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -35,10 +35,13 @@ For suspected vulnerabilities, don't open a public issue. Follow the private rep
3535
├── skills/java-optionals/
3636
│ ├── SKILL.md
3737
│ ├── agents/openai.yaml
38-
│ ├── evals/evals.json
3938
│ └── references/
40-
│ ├── optional-examples.md
41-
│ └── source-notes.md
39+
│ ├── java-optional-api.md
40+
│ └── optional-examples.md
41+
├── docs/agents/
42+
│ ├── eval-case-inventory.md
43+
│ ├── legacy-evals.json
44+
│ └── source-notes.md
4245
├── AI_CONTRIBUTION_POLICY.md
4346
├── CODE_OF_CONDUCT.md
4447
├── CONTRIBUTING.md
@@ -50,12 +53,14 @@ For suspected vulnerabilities, don't open a public issue. Follow the private rep
5053
requests.
5154
- `skills/java-optionals/SKILL.md` is the runtime instruction file loaded by agents.
5255
- `skills/java-optionals/agents/openai.yaml` provides display metadata.
53-
- `skills/java-optionals/references/optional-examples.md` contains larger examples and eval case
54-
notes.
55-
- `skills/java-optionals/references/source-notes.md` records where the skill came from and why it
56-
changed over time.
57-
- `evals/` contains the hosted Tessl implementation-regression benchmark used for the headline
58-
README score.
56+
- `skills/java-optionals/references/optional-examples.md` contains runtime-safe examples.
57+
- `skills/java-optionals/references/java-optional-api.md` records Java 8 through Java 26
58+
Optional-family compatibility guidance.
59+
- `docs/agents/eval-case-inventory.md`, `docs/agents/legacy-evals.json`, and
60+
`docs/agents/source-notes.md` are maintainer-only material and must not be linked from runtime
61+
skill references.
62+
- `evals/` contains the hosted Tessl implementation-regression benchmark used for headline
63+
reporting.
5964
- `evals-reference/` keeps extra review and test scenarios that are useful during development but
6065
aren't part of the headline benchmark.
6166
- `scripts/` contains portable validation checks used by CI.
@@ -82,23 +87,32 @@ Run these before committing skill, eval, README, package, script, or CI changes:
8287
```bash
8388
python3 scripts/validate_skill.py skills/java-optionals
8489
python3 scripts/validate_eval_criteria.py evals evals-reference
90+
python3 -m py_compile scripts/validate_skill.py scripts/validate_eval_criteria.py
91+
bash -n scripts/check_publish_dry_run.sh
8592
tessl plugin lint .
8693
```
8794

8895
If you change the skill text or reference files, also run:
8996

9097
```bash
91-
tessl skill review --threshold 100 skills/java-optionals/SKILL.md
98+
tessl skill review --threshold 90 skills/java-optionals/SKILL.md
9299
```
93100

101+
The threshold is intentionally below 100 so useful, specific guidance doesn't get removed only to
102+
make the review score look cleaner. Treat the review output as a quality signal and address valid
103+
feedback.
104+
94105
If you have Tessl access, you can also run the publish dry-run:
95106

96107
```bash
97108
bash scripts/check_publish_dry_run.sh .
109+
tessl plugin publish --dry-run --bump patch .
98110
```
99111

100-
That dry-run may fail because the current version already exists in the registry. That's expected
101-
after a version has already been published; any other failure needs investigation.
112+
The script runs the fast skipped-eval package smoke check and retries with a patch bump if the
113+
current version already exists. The full `tessl plugin publish --dry-run --bump patch .` command is
114+
a PR-safe full eval-ingesting dry-run. Release publishing uses an exact-version dry-run before the
115+
real publish command.
102116

103117
`tessl skill review`, `bash scripts/check_publish_dry_run.sh .`, and hosted evals require Tessl
104118
authentication. Hosted evals also require a linked Tessl project. If you don't have access, include
@@ -186,14 +200,18 @@ tessl eval run --variant with-context --variant without-context .
186200
If you don't have a Tessl workspace, that's fine. Open the pull request with the local check results,
187201
and a maintainer can run the hosted evals before release.
188202

189-
The headline benchmark should stay focused on implementation tasks that mirror the motivating
190-
failures. Broad review and smoke scenarios can live in `evals-reference/` unless they're part of the
191-
headline measurement.
203+
The headline benchmark should stay focused on realistic tasks that mirror the motivating failures.
204+
It must include a documented mix of natural activation prompts and explicit invocation prompts.
205+
Natural scenarios must not mention `$java-optionals` or ask to use the skill. Explicit scenarios may
206+
name the skill and must be labeled as explicit in `criteria.json`.
207+
208+
Every scenario directory must contain `task.md`, `criteria.json`, and `capability.txt`. Headline
209+
implementation criteria must include compile/artifact checks and behavior correctness checks before
210+
Optional style checks. Do not move or hide baseline-solved scenarios just to improve lift; keep broad
211+
coverage in `evals-reference/` and report it separately.
192212

193-
The broader review scenarios in `evals-reference/` are useful while developing the skill, but many
194-
are small snippets that a strong generic model can already solve without the skill. Keep them as
195-
reference coverage unless they reveal a real implementation failure that belongs in the headline
196-
benchmark.
213+
Runtime skill references must not contain eval inventories, expected answers, score rubrics, hosted
214+
run IDs, or benchmark claims. Put maintainer-only eval history in `docs/agents/`.
197215

198216
## Benchmark Updates
199217

@@ -203,7 +221,9 @@ When the hosted benchmark changes:
203221
- record the content commit;
204222
- update baseline and skill scores;
205223
- update lift, raw score ratio, and missed-point reduction;
206-
- keep the README wording clear about what the benchmark measures.
224+
- report natural activation, explicit invocation, headline combined, and reference/full results
225+
separately when available;
226+
- keep the README wording clear about what the benchmark measures and avoid stale fixed claims.
207227

208228
## Release Checklist
209229

0 commit comments

Comments
 (0)