{
 "date": "2026-10-25",
 "timezone": "Asia/Shanghai",
 "issue": 46,
 "batch": "U09",
 "sourceTag": "OpenJDK jdk-17.0.12+7 (fixed mechanism source)",
 "environment": {
  "os": "macOS 26.7.1 (25G241, x86_64)",
  "architecture": "x86_64",
  "javaVersion": "java version \"17.0.12\" 2024-07-16 LTS\nJava(TM) SE Runtime Environment (build 17.0.12+8-LTS-286)",
  "javaHome": "/Library/Java/JavaVirtualMachines/jdk-17.jdk/Contents/Home",
  "runtimeNote": "与 U05/U06/U07/U08 相同的本机 Oracle JDK 17.0.12+8（x86_64）。绿跑开始于 2026-10-24T19:15:20Z（北京时间 2026-10-25 03:15）。",
  "runPolicy": "每次运行由包装命令设置 90 秒（all 模式 300 秒）perl alarm 上限、JAVA_TOOL_OPTIONS=-Xmx256m、唯一 TMPDIR 并作为 java.io.tmpdir 传入；run.sh 自身 mktemp 唯一编译目录 + EXIT/INT/TERM trap。探针所有闩锁/join 等待上限 5 秒、定时观察用有界 poll（500ms–5s），所有线程池在 finally 关闭并 awaitTermination 断言；反射观察段访问被拒时打印 SKIP 不失败。",
  "stderrNote": "『Exception in thread \"exits-1\" java.lang.IllegalStateException: execute-boom』是第 2 节 execute() 逃逸异常经线程未捕获处理器的预期打印——正是 submit() 静默路径的对照证据，不是故障；『注: TypeProbe.java 使用了未经检查或不安全的操作』来自 run.sh 固定编译列表中的既有 TypeProbe.java，非本票输出；『Picked up JAVA_TOOL_OPTIONS』是 JVM 对显式内存/临时目录限制的回显（该回显混入 run.sh 版本守卫读取时也如实呈现，见 no-java-home-fallback-21 一行）。"
 },
 "tdd": {
  "redGreen": [
   "红1（shutdown 丢队列任务误解，2026-10-24T19:05Z 前后）：按常见误解写下断言『shutdown() 后队列中未执行的任务会被丢弃』（/tmp/u09-red/PoolAsyncProbeRed.java red1：queuedRan 应为 false），实跑 exit=1，AssertionError: RED1 unexpected: queued task executed after shutdown (misconception said it would be dropped)——SHUTDOWN 继续消费队列，排队任务照常执行；修正断言为『队列任务必须执行』后绿跑通过。正文关闭段按『停止接纳、继续收尾』口径撰写。",
   "红2（afterExecute 能看到 submit 异常的误解，2026-10-24T19:08Z 前后）：按『submit 抛错会经钩子/控制台暴露』的误解断言 afterExecute 收到该异常（red2 要求 Throwable 非 null），实跑 exit=1，AssertionError: RED2 unexpected: afterExecute got null —— submit 的用户异常被 FutureTask 捕获，钩子收到 null、无控制台输出、线程不重建；修正方向后以『钩子收到 null + Future.get 抛 ExecutionException + 同一 worker 保留』三断言落进绿探针第 2 节。首个红测脚本方向曾写反（断言误解为假）且漏关池导致 JVM 挂起，属测试脚本缺陷如实记录，重写后取得真实红。",
   "红3（中断标志保持误解，2026-10-24T19:10Z 前后）：按『捕获 InterruptedException 后标志位仍为 true』的误解断言 catch 内 isInterrupted() 为 true（red3），实跑 exit=1，AssertionError: RED3 unexpected: interrupt flag still set inside catch (misconception said it stays)——异常抛出即清除标志；修正后绿探针第 7 节按『catch 内 false -> 恢复 -> true -> interrupted() true -> false』四步断言。"
  ],
  "compileFixes": "开发期修复如实记录不计红绿：(1) CF.cancel 场景首版未钉住 supplier 已启动，AsyncSupply.run() 的 result==null 检查在 cancel 先到时整个跳过 supplier（实测 effects=0、断言失败 exit=1）——加 started 闩锁钉住『已运行再取消』后稳定；该竞态本身作为教学点写入正文（未启动任务可能根本不执行）。(2) 红测脚本 red2 漏 pool.shutdown() 使非 daemon 工作线程挂住 JVM（进程不退出），补 finally 关闭——『未关闭池的最小症状』借此如实登记。(3) orTimeout/completeOnTimeout 两场景首版共用一个释放闩锁，第二场景会因闩锁已开而提前完成，拆分 releaseA/releaseB。",
  "noFakeRed": "三个红均为先按常见误解写下的真实预期（shutdown 丢队列、钩子可见 submit 异常、中断标志保持）被 JDK17 实测推翻，随后按源码/API 契约修正转绿，不倒造 red。"
 },
 "runs": [
  {
   "name": "poolasync-final",
   "command": [
    "bash",
    "labs/java-senior/run.sh",
    "poolasync"
   ],
   "env": {
    "JAVA_HOME": "/Library/Java/JavaVirtualMachines/jdk-17.jdk/Contents/Home"
   },
   "startedUtc": "2026-10-24T19:15:20+00:00",
   "timeoutSeconds": 90,
   "timedOut": false,
   "exit": 0,
   "stdout": "java.version=17.0.12 vm=Java HotSpot(TM) 64-Bit Server VM\n\n== 1. shutdown vs shutdownNow: queue draining and interruption scope ==\nshutdown(): new task rejected, but queued task still executed（SHUTDOWN 停止接纳、继续消费队列；中断只打向空闲 Worker）\nshutdownNow(): returned 1 queued task (never executed); running task exited via InterruptedException（STOP 全量中断而非仅空闲，队列被搬走而非继续消费）\nshutdownNow() on interrupt-blind task: worker alive after 300ms=true（观察值——API 只承诺尽力中断，不承诺终止）\nworker exited only after its own stop flag was set（协作取消缺位时关闭有界等待是唯一兜底）\nPASS shutdown/shutdownNow semantics and unresponsive-task boundary\n\n== 2. task exception: execute vs submit, afterExecute observation ==\nexecute(throws): afterExecute received \"execute-boom\"; worker thread exits-1 died\nreplacement worker for follow-up task: exits-1 -> exits-2（逃逸异常导致 Worker 重建）\nsubmit(throws): afterExecute received null; Future.get -> ExecutionException(\"submit-boom\"); worker exits-2 retained（异常被 FutureTask 捕获，不重建线程）\nPASS task-exception exits: hook visibility, worker replacement, Future.get exposure\n\n== 3. rejection: CallerRuns both branches and DiscardOldest head-drop ==\nCallerRunsPolicy while RUNNING: third task executed on caller thread \"main\"（提交者被反压，不是池并行度变大）\nCallerRunsPolicy after shutdown(): task silently discarded, no exception thrown（关闭后的丢弃分支常被误记为“一定执行”）\nDiscardOldestPolicy: queue head B dropped, newcomer D accepted; order=[A, C, D]\nPASS rejection branches (Abort trigger asserted by SeniorProbe pool history)\n\n== 4. keepAlive and allowCoreThreadTimeOut ==\nallowCoreThreadTimeOut(true) + keepAlive=200ms: idle pool size -> 0（核心线程也会回收；前置条件 keepAlive>0）\ndefault core retention: after 800ms idle, pool size=1（keepAlive 默认只回收超出 core 的空闲线程）\nkeepAlive=100ms does not interrupt a 400ms running task（只控空闲，不是任务超时）\nPASS keepAlive boundaries\n\n== 5. CompletableFuture chain: exception propagation and recovery ==\nsource fails -> thenApply downstream join throws CompletionException(same cause)（异常沿依赖图传播，不经过恢复节点就是同因失败）\nexceptionally(0).thenApply(+1) -> 1（恢复节点之后的下游收到正常值）\nwhenComplete observes cause but its stage stays failed; handle -> -1（观察不等于恢复）\nallOf(failed, slow-success): join throws, but slow stage IS done（等全部完成才报告）\nanyOf: first completed was the failure -> join throws（最先完成不等于最先成功）\nPASS CF chain propagation/recovery/waiting semantics\n\n== 6. orTimeout vs completeOnTimeout ==\norTimeout(150ms): get threw TimeoutException; after release effects=2（已启动的底层计算继续，迟到的结果被丢弃——终态不回滚）\ncompleteOnTimeout(\"fallback\",150ms): get -> \"fallback\"; late \"real\" cannot overwrite（降级成为正常值，错误率指标要另记）\nPASS timeout completion strategies\n\n== 7. interrupt protocol: flag, clearing, restore ==\nbusy loop on isInterrupted(): observed flag, exited（不经过阻塞方法也能协作取消）\nInterruptedException path: flag cleared in catch=true; after restore=true; Thread.interrupted()=true then false（静态方法读取并清除，isInterrupted 不清除）\nPASS interrupt protocol branches\n\n== 8. cancel cooperation: blind vs cooperative task, CF.cancel ==\ncancel(true) on interrupt-blind task: thread still alive 250ms later; computation finished (effects=1); get -> CancellationException（取消只赢得结果槽，不占有线程的退出权）\ncancel(true) on cooperative task: InterruptedException observed, exited promptly, effects=0\nCF.cancel(true): stage cancelled, worker NOT interrupted (effects stayed 0 until release), supplier still ran（布尔参数在此实现不控制线程）\nPASS cancellation cooperation matrix\n\n== 9. ThreadLocal: stale reads, remove, InheritableThreadLocal, decorator ==\ntask2 read ThreadLocal=\"request-1\" left by request-1 on the same pooled thread（池复用串请求）\ntask with finally-remove: next task reads null（清理责任在任务侧，不在线程侧）\nInheritableThreadLocal: value set AFTER pool thread creation -> task reads null（只在 Thread 构造时快照，不随提交传播）\ncontrol: fresh thread created now inherits \"parent-late\"\ncapture-restore decorator: task saw trace=req-abc; after task the pool thread is back to {trace=pool-resident}（安装/恢复都在任务侧闭环）\nPASS ThreadLocal lifecycle and context propagation\n\n== 10. ThreadLocalMap stale entry (reflection observation, not a contract) ==\nafter GC hint: table entries live=0 stale(key cleared, value alive)=1（观察值非契约：清理只发生在后续表操作，弱键不等价于值立即回收）\n\nALL U09 SECTIONS PASS\n",
   "stderrNote": "execute-boom 未捕获异常打印与 JAVA_TOOL_OPTIONS 回显，见 environment.stderrNote",
   "tmpLeft": 0,
   "stabilityNote": "终轮前同二进制独立直跑连续 3 轮 exit=0 全绿（/tmp 独立目录，已清理）；计时类观察（300ms 存活、800ms 保留、150ms 超时）按轮打印不断言精确耗时；GC 观察段只打印不断言。"
  },
  {
   "name": "unknown-mode",
   "command": [
    "bash",
    "labs/java-senior/run.sh",
    "nonsense"
   ],
   "exit": 2,
   "stdout": "Usage: run.sh [all|locks|pool|async|poolasync|jmm|sync|algorithms|types|reflect|collections|library|io]",
   "note": "未知模式退出 2（用法串含 poolasync）"
  },
  {
   "name": "extra-arg",
   "command": [
    "bash",
    "labs/java-senior/run.sh",
    "poolasync",
    "extra"
   ],
   "exit": 2,
   "note": "参数过多退出 2"
  },
  {
   "name": "bad-java-home",
   "command": [
    "bash",
    "labs/java-senior/run.sh",
    "poolasync"
   ],
   "env": {
    "JAVA_HOME": "/bad/home"
   },
   "exit": 2,
   "note": "无效 JAVA_HOME 退出 2（JDK 工具缺失）"
  },
  {
   "name": "jdk21-rejected",
   "command": [
    "bash",
    "labs/java-senior/run.sh",
    "poolasync"
   ],
   "env": {
    "JAVA_HOME": "/Library/Java/JavaVirtualMachines/jdk-21.jdk/Contents/Home"
   },
   "exit": 2,
   "note": "版本守卫拒绝 JDK21（java version 21.0.5），本入口固定 JDK17"
  },
  {
   "name": "no-java-home-fallback-21",
   "command": [
    "bash",
    "labs/java-senior/run.sh",
    "poolasync"
   ],
   "env": {
    "JAVA_HOME": ""
   },
   "exit": 2,
   "note": "未显式设 JAVA_HOME 时本机 java_home 解析到 21.0.5，版本守卫同样拒绝并退出 2——文档化入口要求显式 JAVA_HOME 指向 17"
  },
  {
   "name": "all-final",
   "command": [
    "bash",
    "labs/java-senior/run.sh",
    "all"
   ],
   "env": {
    "JAVA_HOME": "/Library/Java/JavaVirtualMachines/jdk-17.jdk/Contents/Home"
   },
   "startedUtc": "2026-10-24T19:15:52+00:00",
   "timeoutSeconds": 300,
   "timedOut": false,
   "exit": 0,
   "stdoutNote": "含 SeniorProbe locks/pool/async（历史探针原样通过，PASS core=1 max=2 queue=1 fourth task rejected、PASS DiscardPolicy leaves submitted Future unfinished 等四条在列）、AlgorithmProbe、TypeProbe+编译检查、ReflectionProbe、JmmProbe（U07，ALL U07 SECTIONS PASS）、LocksProbe（U08，ALL U08 SECTIONS PASS）、PoolAsyncProbe（U09，ALL U09 SECTIONS PASS）、collections、library、io（ALL U06 SECTIONS PASS 收尾）全部正常结束，361 行输出",
   "tmpLeft": 0
  }
 ]
}
