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

tballison pushed a commit to branch refactor-skills
in repository https://gitbox.apache.org/repos/asf/tika.git

commit 566e9f31f0ae16f00ee4781026ac4282fe1229d5
Author: tallison <[email protected]>
AuthorDate: Mon Jul 27 12:04:06 2026 -0400

    refactor skills to be directory based
---
 .skills/{dev.md => dev/SKILL.md}                   |  13 +-
 .skills/pr-review/SKILL.md                         | 239 +++++++++++++++++++++
 .../SKILL.md}                                      |  11 +
 .../SKILL.md}                                      |  12 ++
 .../SKILL.md}                                      |  11 +
 5 files changed, 285 insertions(+), 1 deletion(-)

diff --git a/.skills/dev.md b/.skills/dev/SKILL.md
similarity index 89%
rename from .skills/dev.md
rename to .skills/dev/SKILL.md
index 52ae923460..3931b86276 100644
--- a/.skills/dev.md
+++ b/.skills/dev/SKILL.md
@@ -1,3 +1,14 @@
+---
+name: dev
+description: >
+  Core guidelines and checklist for developing against the Apache Tika 
codebase:
+  git policy (never commit/push for the user), Maven rules (always `clean`,
+  absolute `-Dmaven.repo.local`, `-Pfast` for quick builds, install before 
forked
+  pipes tests), module paths, code conventions (no machine-specific paths, ASF
+  headers, spotless), and pre-commit checks. Use whenever building, testing, or
+  preparing a change to Tika.
+---
+
 # Tika Development Skill
 
 Guidelines and checklist for developing against the Apache Tika codebase.
@@ -97,7 +108,7 @@ provide the suggested commit message for the user to execute.
 
 When a change affects parsing output (e.g., new parser behavior,
 encoding fix), run a before/after comparison using tika-eval.
-See `.skills/tika-eval-compare.md` for the full procedure.
+See `.skills/tika-eval-compare/SKILL.md` for the full procedure.
 
 ## Pre-Commit Checks
 
diff --git a/.skills/pr-review/SKILL.md b/.skills/pr-review/SKILL.md
new file mode 100644
index 0000000000..05f096eaa5
--- /dev/null
+++ b/.skills/pr-review/SKILL.md
@@ -0,0 +1,239 @@
+---
+name: pr-review
+description: >
+  Review a GitHub pull request (or a local branch) against Apache Tika. Fetches
+  the PR, reads the linked JIRA + review thread, builds and tests the ACTUALLY
+  affected modules (not just the changed one), and hunts the regressions that
+  slip past module-local builds. Use for "review PR #NNNN", "look at this PR",
+  "can you review https://github.com/apache/tika/pull/NNNN";.
+---
+
+<!--
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+
+# Review an Apache Tika Pull Request
+
+Goal: produce a review that a maintainer can act on — grounded in the code as
+it actually is, with every substantive claim verified by building/running, not
+by reading alone. Report findings ranked by severity, and say plainly what you
+checked and what you did not.
+
+## Output rules
+
+- **Never post to GitHub.** No PR/issue comments, reviews, labels, approvals.
+  Read-only `gh` is fine. Deliver the review as text in the chat for the user
+  to post themselves. (This mirrors the user's standing instruction.)
+- **Never commit.** If you draft a fix, stage it or paste a diff; the user
+  commits.
+- Lead with a one-line verdict (mergeable? blockers?), then findings
+  most-severe first, then the routine/nit items, then "what I verified."
+
+## 1. Gather context (do all of this before judging anything)
+
+```bash
+gh pr view <N> --repo apache/tika \
+  --json number,title,author,state,body,files,additions,deletions,\
+baseRefName,headRefName,url,comments
+gh pr diff <N> --repo apache/tika
+```
+
+- Read the **linked JIRA** — the PR title is usually `TIKA-XXXX: ...`. Fetch 
it;
+  the issue often lists a *proposed fix* with specific requirements the PR must
+  satisfy (and sometimes a superset the PR deliberately scoped down):
+  `curl -s 
"https://issues.apache.org/jira/rest/api/2/issue/TIKA-XXXX?fields=summary,description,comment"`
+- **Read the existing PR review thread.** Reviewers (and their agents) often
+  already asked for changes. Check each requested change against the *current*
+  head — authors iterate, and a later commit may have **reverted** an earlier
+  one. Diff the commits (`git log --oneline base..head`, `git show <sha>`) so 
you
+  review the final state, not commit 1.
+- **Don't assume a bot pre-reviewed.** Copilot coverage is going away, so you 
now
+  own the full mechanical pass (§4) *and* the judgment (§5). If prior bot/agent
+  comments exist, adjudicate them (confirm/refute — §6); otherwise do the pass
+  yourself.
+
+## 2. Get the branch and build the RIGHT modules
+
+Use a throwaway worktree so you never disturb the user's checkout:
+
+```bash
+git fetch origin pull/<N>/head:pr-<N>
+git worktree add "$SCRATCH/pr-<N>" pr-<N>
+```
+
+Build with the repo's rules (see `.skills/dev/SKILL.md`): `./mvnw`, always 
`clean`,
+absolute `-Dmaven.repo.local`, `-Pfast` for a quick pass.
+
+> **The trap that hides real bugs:** building only the changed module is not
+> enough. A change to a *shared* type (an enum, an interface, a public method
+> signature, a serialized field) can compile cleanly in its own module and
+> **break a downstream module that recompiles against it.** Always ask: *who
+> consumes the thing that changed, and did I compile them?*
+>
+> Concretely, if the diff touches `tika-pipes-api` / `tika-core` / any
+> `*-api` module, compiling just that module proves almost nothing. Compile the
+> consumers too (`tika-server-core`, `tika-pipes-fork-parser`, `tika-grpc`,
+> `tika-app`, …). A full `./mvnw clean install` from the root is the honest
+> check when you have time.
+
+Run the PR's own new/changed tests, and the surrounding module's suite:
+
+```bash
+$SCRATCH/pr-<N>/mvnw -f $SCRATCH/pr-<N>/pom.xml clean install \
+  -pl :<changed-module> -am -Dmaven.repo.local=<abs>/.local_m2_repo
+```
+
+Do a run **without** `-Pfast` on the changed module before you bless it, so
+checkstyle + spotless run (Tika gates on both).
+
+## 3. High-yield checks (these catch the most in Tika)
+
+- **Enum constant added to an exhaustive `switch`.** Java `switch`
+  *expressions* over an enum with no `default` are exhaustive-checked at 
compile
+  time. Adding a constant turns every such switch into a **compile error** — in
+  whatever module owns the switch, which is usually *not* the module that
+  changed. Grep for consumers: `grep -rn "switch" --include=*.java | grep 
<EnumType or the switched var>`
+  and check each for arrow-form `return switch (x) { ... };` with no `default`.
+  (`switch` *statements* don't require exhaustiveness — they compile but may
+  silently miss the new case; flag those as behavior gaps, not build breaks.)
+- **New public field / config option → is it actually wired end to end?**
+  Trace every read site of the old constant/limit and confirm the new
+  configurable value reaches *all* of them (or that the ones it skips are
+  intentional and documented). A config that only takes effect on one of two
+  ends is a common half-wiring.
+- **Docs vs. code.** Read the javadoc/CHANGES/README the PR adds or touches
+  against what the code now does. Iterated PRs frequently leave a javadoc
+  describing an *earlier* commit's behavior (e.g. "configures both ends" after
+  a later commit made it one end). This is exactly the kind of thing that reads
+  as done but isn't.
+- **New enum status / result code plumbed to the surface?** If the change adds 
a
+  result/status, follow it to where users see it (HTTP response mapping, CLI
+  exit code, serialized output). tballison's recurring ask: *surface the real
+  cause* rather than collapsing it into a generic crash/500.
+- **Error/stream handling correctness.** For IPC/socket/stream code: after an
+  error, is the stream left synchronized or torn down? Is a "healthy, no
+  restart" claim actually true for the *default* configuration (e.g. Tika's
+  `useSharedServer` default is `false` → per-client forked server; a broken
+  pipe there still kills the process regardless of client-side handling)? 
Verify
+  the claim against the default path, not just the convenient one.
+- **CHANGES.txt.** Tika lists every change under the current unreleased version
+  with its `(TIKA-XXXX)`. A PR with no CHANGES.txt entry is usually incomplete
+  (often fixed at merge, but call it out).
+- **Catch-block ordering / exception hierarchy.** A new exception subclass must
+  be caught before its supertype; confirm it compiles and that the intended
+  handler actually wins.
+
+## 4. Tika recurring-issue checklist (verify, don't just echo)
+
+Ranked by how often reviews hit them. You own this pass now — work it top to
+bottom; verify each hit.
+
+**Resource / stream lifecycle** (densest cluster)
+- `parse()` must NOT close the caller's `InputStream`; closing a 
`TikaInputStream`
+  that wraps it closes it via `TemporaryResources`.
+- Close per-entry/zip streams; try-with-resources so cleanup survives 
exceptions.
+- Temp files: prefer delete-on-`TikaInputStream`-close (see `S3Fetcher`); avoid
+  unconditional `deleteOnExit()`; delete on exception. Null a field after
+  `close()`; shut down `Executors`; cache `URLClassLoader` (Windows jar-lock).
+
+**Exceptions**
+- Exception-in-`finally` masking the real one — esp. draining XHTML balancing
+  handlers only on `SAXException` when `IOException`/`TikaException` also 
escape,
+  so `endDocument()` throws on unbalanced elements. Drain for all escaping 
types.
+- No silent swallow (log at least); catch specific exceptions by behavior; 
custom
+  exceptions extend `TikaException`.
+
+**Stream reading**
+- Don't trust `skip()`/`read()` returns — use `IOUtils.skipFully`/`readFully`,
+  check length. (`IOUtils.read` returns `[0,len]`, never `-1`.)
+
+**Thread-safety** — parsers stateless/thread-safe, no mutable instance fields.
+`Metadata` field leak: a value set conditionally but never cleared bleeds into
+the next parse on a reused `Metadata`.
+
+**Config (Jackson)** — param names map to setters by JavaBean rules (`skipOcr`,
+not `skipOCR`); don't hand-track "userConfigured"; watch resource-exhaustion
+defaults; array- vs object-form JSON schema changes break checked-in configs.
+
+**Maven/POM** — no local version pins (use `tika-parent` dependencyManagement);
+match `main`'s `X.Y.Z-SNAPSHOT`; no duplicate plugin blocks; ASF license header
+(RAT) on every new file incl. test resources.
+
+**Tests** — coverage for new class/factory/method; no nonexistent resource 
files;
+no net downloads in `@BeforeAll`; no `lsof`/`kill`/`docker` assumed present, 
use
+`assumeTrue(exe present)`; restore global state (timezone, ServiceLoader CCL); 
a
+disabled test often hides a real regression — flag it.
+
+**Numeric/boundary** — range-check offsets/sizes from container bytes; int
+overflow from corrupt models; `getFileName()` NPE at FS root; code points >
+`Character.MAX_CODE_POINT` into `Character.*`.
+
+**XHTML output** — emit real markup (`<div class="section">`, `<p>`), not raw
+body writes; balanced/nested close. Leave `XHTMLContentHandler` alone (no
+auto-close/suppression — fix the parser or let it throw).
+
+**Docs & style** — javadoc/README/adoc claims vs actual code (rename drift,
+omitted fields, "order irrelevant"); correct JIRA id; runnable commands; no
+real-looking secrets; no machine-specific paths; no wildcard imports; drop
+unrelated formatter/import churn.
+
+## 5. Go beyond the mechanical pass (judgment a bot won't apply)
+
+- **Necessity / altitude** — "Is this needed? Does it justify the code +
+  maintenance? Simpler/safer way?" Don't guess system paths (portability).
+- **Scope discipline** — unrelated whitespace/bugfixes → separate commit/PR; 
keep
+  the diff surgical.
+- **Cross-module + security reasoning** (see §3) — downstream compile breaks;
+  defense-in-depth (e.g. XML entity resolver empty-string trap).
+
+## 6. Known false positives — reproduce before re-raising
+
+- `ByteBuffer.wrap(arr, off, len)` starts at position `off`, not 0 (only 1-arg
+  `wrap` starts at 0).
+- `IOUtils.read` returns `[0,len]`, never `-1` — a `-1` check is not "missing".
+- "Our own file" / test fixtures → no `SecurityException`; file expected 
present.
+- A plausible read is not a bug. Reproduce, or cite the exact contract, first.
+
+## 7. Verify, don't assert
+
+For every non-trivial finding, prove it:
+
+- Compile break → show the compiler error (build the consumer module).
+- "This test doesn't cover X" → add/trace the case and show it.
+- Behavioral claim → a tiny probe `main()` on the built classpath beats
+  speculation. Build a classpath with
+  `mvn dependency:build-classpath -Dmdep.outputFile=cp.txt` and run with a JDK
+  matching the module's bytecode target.
+
+Distrust smoothness: the more obviously-fine a shared-type change looks, the
+more it earns a downstream compile.
+
+## 8. Write it up
+
+- **Verdict** first: is it mergeable as-is? What's the blocker?
+- **Blockers** (build breaks, correctness bugs) with the evidence.
+- **Design / should-fix** (half-wiring, stale docs, narrow-benefit claims).
+- **Nits** (CHANGES.txt, PR-description drift, naming).
+- **What I verified** — modules built, tests run, probes executed — and what I
+  deliberately did *not* check, so the maintainer knows the edges of the 
review.
+- If you wrote a fix, include it as a diff/patch; do not commit or push.
+
+## Cleanup
+
+```bash
+git worktree remove "$SCRATCH/pr-<N>" --force
+git branch -D pr-<N>   # optional
+```
diff --git a/.skills/tika-eval-compare.md b/.skills/tika-eval-compare/SKILL.md
similarity index 93%
rename from .skills/tika-eval-compare.md
rename to .skills/tika-eval-compare/SKILL.md
index cdb581e386..fab60f02bc 100644
--- a/.skills/tika-eval-compare.md
+++ b/.skills/tika-eval-compare/SKILL.md
@@ -1,3 +1,14 @@
+---
+name: tika-eval-compare
+description: >
+  Compare the output of two Tika versions against a corpus to catch regressions
+  in content extraction, encoding, exceptions, and embedded-document handling
+  before a release. Covers building the two tika-app distros, generating
+  extracts, running tika-eval Compare, and the mandatory review checklist 
(never
+  bless a run on dice scores alone — check the total-files delta). Use for 
"run a
+  before/after eval", "check for regressions", "tika-eval compare".
+---
+
 # tika-eval: Compare Before/After Extracts
 
 Compare the output of two versions of Tika against a corpus of files
diff --git a/.skills/tika-eval-encoding-regression.md 
b/.skills/tika-eval-encoding-regression/SKILL.md
similarity index 94%
rename from .skills/tika-eval-encoding-regression.md
rename to .skills/tika-eval-encoding-regression/SKILL.md
index 7532df3981..c6ca6d4223 100644
--- a/.skills/tika-eval-encoding-regression.md
+++ b/.skills/tika-eval-encoding-regression/SKILL.md
@@ -1,3 +1,15 @@
+---
+name: tika-eval-encoding-regression
+description: >
+  Condensed pattern for hunting charset/encoding-detector regressions (SBCS→CJK
+  style, or any "A picks encoding X, B picks Y" question) by running two 
configs
+  against a single tika-app build instead of two distributions. Covers the
+  canonical detector-chain configs, the encoding-flip SQL, reading OOV /
+  languageness / U+FFFD together, per-file detector attribution
+  (X-TIKA:encodingDetectionTrace), and single-file reproduction. Use for
+  encoding/charset-detector eval work.
+---
+
 # tika-eval for encoding-detector regression hunts
 
 A condensed pattern for finding SBCS→CJK style charset-detector regressions
diff --git a/.skills/tika-eval-h2-query.md b/.skills/tika-eval-h2-query/SKILL.md
similarity index 92%
rename from .skills/tika-eval-h2-query.md
rename to .skills/tika-eval-h2-query/SKILL.md
index 37532d64c0..5cc95f79de 100644
--- a/.skills/tika-eval-h2-query.md
+++ b/.skills/tika-eval-h2-query/SKILL.md
@@ -1,3 +1,14 @@
+---
+name: tika-eval-h2-query
+description: >
+  Query the tika-eval H2 database directly (the `-d <name>` from Compare 
produces
+  `<name>.mv.db`) for exact counts, custom joins, and better-vs-worse tallies 
the
+  xlsx/summary.md reports don't compute. Covers the no-username/no-password
+  connect gotcha, key tables (PROFILES/CONTENTS/ENCODINGS/CONTENT_COMPARISONS),
+  paired-by-id joins, and the silent case-sensitive REGEXP trap. Use when the
+  canned tika-eval reports aren't enough.
+---
+
 # Query the tika-eval H2 database directly
 
 `tika-eval` (Compare / Profile / Report) stores everything in an **H2** 
database

Reply via email to