用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
直接命令不会经过审查 Prompt;运行前请先检查来源。
npx skills add https://github.com/ben-manes/caffeine --skill audit-map-contract命令会保持在同一行。复制前请横向滚动并检查完整内容。
想先保存到本地?可下载 SkillsMP 当前能够提供的文件。
基于 SOC 职业分类
正在显示 SKILL.md
| name | audit-map-contract |
| description | Audit ConcurrentMap and Map contract compliance for asMap() view |
| context | fork |
| agent | auditor |
| disable-model-invocation | true |
Audit compliance with java.util.concurrent.ConcurrentMap and java.util.Map contracts,
and Caffeine's alignment with the Java Collections Framework.
The JavaDoc is silent or ambiguous on the behaviors that actually bite (null inside a bulk
collection arg, containsAll(self), equals across map types, the optional NPE points,
default-method bodies). WebFetch the real source and read the method body before
asserting a contract. Track master (latest) — we stay pragmatically current, not pinned
to a JDK version. Fetch the raw form (raw.githubusercontent.com/openjdk/jdk/master/src/ java.base/share/classes/…), not the blob page. These files are large (CHM ~6500 lines)
and WebFetch answers a prompt over the content with a small model, so a generic "dump the
file" truncates — prompt for the specific method ("quote the exact body of
CollectionView.containsAll"), one method per fetch:
asMap() is a ConcurrentMap and closest
to CHM:
https://raw.githubusercontent.com/openjdk/jdk/master/src/java.base/share/classes/java/util/concurrent/ConcurrentHashMap.javaConcurrentMap; the tie-breaker on whether a
divergence from CHM is legal (e.g. it also throws UOE on entrySet().add, where CHM's
put-through is a nonstandard v8-rewrite addition):
https://raw.githubusercontent.com/openjdk/jdk/master/src/java.base/share/classes/java/util/concurrent/ConcurrentSkipListMap.javagetOrDefault, compute*, merge,
replaceAll):
https://raw.githubusercontent.com/openjdk/jdk/master/src/java.base/share/classes/java/util/concurrent/ConcurrentMap.javahttps://raw.githubusercontent.com/openjdk/jdk/master/src/java.base/share/classes/java/util/Map.javaAbstractMap.equals,
and via AbstractCollection/AbstractSet the containsAll/removeAll/retainAll loops):
https://raw.githubusercontent.com/openjdk/jdk/master/src/java.base/share/classes/java/util/AbstractMap.javaequals/hashCode comparison target:
https://raw.githubusercontent.com/openjdk/jdk/master/src/java.base/share/classes/java/util/HashMap.javahttps://raw.githubusercontent.com/openjdk/jdk/master/src/java.base/share/classes/java/util/IdentityHashMap.javahttps://raw.githubusercontent.com/openjdk/jdk/master/src/java.base/share/classes/java/util/WeakHashMap.javaLocalCache — the reference for Caffeine's Guava-compat behavior (the
CaffeinatedGuava facade + the uniform null-leniency the philosophy below cites; its
views, removal causes, loader/exception translation):
Be pragmatically close to CHM, but Caffeine may diverge where its behavior is better — and when it does, the divergence must be coherent and recorded (design-decisions.md / the cross-model ledger). Do not treat "differs from CHM" as a bug by itself:
removeAll([null]) throws NPE while
containsAll([null]) returns false — an artifact of which methods happened to get an
explicit null-guard, not a contract. Don't chase CHM's inconsistencies.put/get/containsKey/contains(null) →
NPE — nulls are rejected), but null-tolerant of a null element in a bulk collection
arg (containsAll/removeAll skip it — a null is trivially absent); weakly-consistent
views; size() is an estimate; expired/collected entries filtered from queries and
iteration. The CaffeinatedGuava facade is the deliberate exception — uniformly
null-lenient (Guava-compat), overriding native null-hostility only where Guava diverges.equals across types) has a
legal spread — check several impls (CHM / CSLM / HashMap / Guava), not one, and note
that the collections testlibs usually tolerate both legal choices (e.g. guava-testlib
testContainsAll_nullNotAllowed does assertFalse(...) with catch (NPE tolerated)).
Flag a divergence only when Caffeine is the incoherent one, or diverges from both CHM
and Guava with no better rationale.For any "does Caffeine match CHM/Guava?" question, compile a tiny harness and run Caffeine
side-by-side with real CHM / CSLM / Guava — don't guess (this session, "we mirror CHM"
on containsAll([null]) was empirically wrong — both CHM and Guava return false, Caffeine
NPE'd; and the CHMv8 entrySet().add history was non-obvious):
caffeine/build/libs/caffeine-*.jar (it has the generated
node classes like SSMS; build/classes/java/main does NOT → factory reflection throws),
plus real guava from ~/.gradle/caches/**/guava-*.jar.~/.gradle/jdks/*26*/**/bin/java) — the classes are that bytecode level.timeout … | grep pipeline reports grep's exit code, not gradle's — read the
BUILD line.AsMapTest's map param is polymorphic: compute=ASYNC yields the
async sync-view (LocalAsyncCache.AsMapView), not BLC/ULC — a view change must cover it.:caffeine:googleTest/apacheTest/eclipseTest,
:guava:test) — they encode the contract's tolerated spread.Map contract: equals/hashCode consistency (and across map types — HashMap, TreeMap, IdentityHashMap), putAll atomicity (if weigher throws mid-batch), replaceAll per-entry atomicity, containsValue consistency.
ConcurrentMap contract: compute/computeIfAbsent/merge atomicity ("mapping function applied at most once"), getOrDefault on expired entries, forEach with concurrent mutations, compute returning null (should remove entry), the interface default methods.
Null handling: NPE at the correct points for null keys/values on direct ops;
null elements in bulk args (containsAll/removeAll/retainAll) per the philosophy
above; mapping functions returning null (compute→remove, merge→remove); putIfAbsent(key,
null).
Entry/EntrySet contracts: Map.Entry.setValue() write-through, entrySet remove/contains checking both key AND value, snapshot vs live entries, entrySet().add UOE.
Collection view contracts: keySet()/values()/entrySet() backed by the cache
(bidirectional), contains/containsAll/remove/removeAll/retainAll/removeIf,
containsAll(self) short-circuit, view equals/hashCode over the logical (filtered) set.
Cache semantics interaction: expired-but-present entries visible via asMap()? Collected weak keys visible? asMap() operations triggering listeners? asMap().put() vs cache.put() differences (access time, stats, refresh)? Async raw view vs sync view.
For each finding: quote the requirement from the fetched OpenJDK source (the method + actual body, not remembered JavaDoc), show Caffeine's behavior (ideally via the harness), name the reference spread (CHM / CSLM / HashMap / Guava) and whether Caffeine is coherent, and provide a test case. If Caffeine's divergence is intentional and better, the output is a design-decisions.md / ledger note, not a bug.
asMap()https://raw.githubusercontent.com/google/guava/master/guava/src/com/google/common/cache/LocalCache.java