Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
81 commits
Select commit Hold shift + click to select a range
e8514fd
docs: diagnose version-bump cost anatomy and plan v0.0.3 architecture…
ackness Jul 16, 2026
c2d2672
chore: mark generated data artifacts linguist-generated/-diff
ackness Jul 16, 2026
1a74df1
feat(gamedata): add test-pin snapshot helper with POBR_BLESS_PINS
ackness Jul 16, 2026
13c990c
test: migrate data-content count pins to blessed snapshot
ackness Jul 16, 2026
be69bca
test: replace version-coupled assertions with version-stable guards
ackness Jul 16, 2026
1cecfbd
chore(pipeline): bless test-pin snapshot as regen-all final step
ackness Jul 16, 2026
c806772
feat(pipeline): one-command version bump orchestrator (P1-4)
ackness Jul 16, 2026
1d29900
feat(gamedata): merge version-independent overlay-common special_mods…
ackness Jul 16, 2026
b2dfdb3
chore: teach every special_mods reader the overlay-common layer
ackness Jul 16, 2026
facaa45
data: move version-independent curated special_mods to overlay-common
ackness Jul 16, 2026
3a71571
Merge branch 'worktree-agent-a07de681aeae9d0aa' into v0.0.3-dev
ackness Jul 16, 2026
cf8b571
feat(pipeline): vendor calc-delta report (P0-2)
ackness Jul 16, 2026
dcd9256
Merge branch 'worktree-agent-af7756e8e082bac60' into v0.0.3-dev
ackness Jul 16, 2026
ad92bc5
docs: record v0.0.3 bump-cost items as delivered
ackness Jul 16, 2026
34553f9
feat(gamedata): migrate four curated overlay domains to overlay-common
ackness Jul 17, 2026
60c4b18
chore: point bump pipeline and docs at overlay-common curated domains
ackness Jul 17, 2026
d721113
docs: record pending buff_definitions vendor_ref re-review (15 drifts)
ackness Jul 17, 2026
6a5a08d
test(parity): un-ignore deflection canary after 0.5.4b re-triage
ackness Jul 17, 2026
b293421
feat(parity): admit Refraction buff EvasionGainAsDeflection (0.5.4b #2)
ackness Jul 17, 2026
7148109
Merge branch 'worktree-agent-a43bae850efb7ae2d' into v0.0.3-dev
ackness Jul 17, 2026
78459c9
feat(parity): admit Refraction buff ArmourAppliesTo<El>DamageTaken (0…
ackness Jul 17, 2026
331ca3a
feat(parity): Atziri's Communion spirit-to-life reservation + auto Lo…
ackness Jul 17, 2026
0ff4239
feat(parity): Voices 'Allocates N Sinister Jewel sockets' admits sini…
ackness Jul 17, 2026
ae3c517
test(parity): ratchet baselines for 0.5.4b #4 + un-ignore ember DPS c…
ackness Jul 17, 2026
c2503ac
feat(oracle): ORACLE_EXTRA_STATS ad-hoc per-source stat tabulation
ackness Jul 17, 2026
7c8f5cd
feat(parser): grenade phrases are live SkillType tags again in 0.5.4b…
ackness Jul 17, 2026
4119e81
docs: record 0.5.4b #4 offence DPS clusters in adapting-to-0.5.4b + fmt
ackness Jul 17, 2026
43dbc97
feat(parity): Blazing Critical global fire buff reaches all attacks (…
ackness Jul 17, 2026
8623c74
test(parity): ratchet baselines for 0.5.4b #5 Blazing Critical
ackness Jul 17, 2026
8a4ec9c
docs: record 0.5.4b #5 ailment magnitude triage + Blazing Critical fix
ackness Jul 17, 2026
b932cdf
data: re-review buff_definitions vendor_refs against PoB2 0.22.0 (ce8…
ackness Jul 17, 2026
ebebaba
fix(core): align bifurcate crit pipeline with vendor 0.22.0
ackness Jul 17, 2026
9d5d8dd
fix(build): feed enemyDistance placeholder into skillDist (0.22.0)
ackness Jul 17, 2026
9bccca9
feat(core): support vendor PerStat statList in mod-parser rules
ackness Jul 17, 2026
8f202a0
feat(core): hybrid mana-to-life cost + per-LifeCost mods (Atalui's Bl…
ackness Jul 17, 2026
4bf6d79
fix(core): blend per-leg enemy mitigation in the crit short-circuit path
ackness Jul 17, 2026
9075077
fix(calc): close frost-bomb TotalDPS 0.66x — Archmage gain-as + curse…
ackness Jul 17, 2026
8d99a29
chore(parity): raise baselines for the 0.5.4b #6 AvgDamage-family fixes
ackness Jul 17, 2026
5edb741
fix(data): honor GrantedEffectStatSets RemoveStats — essence-drain Wi…
ackness Jul 17, 2026
6bb0685
fix(calc,data): ritualist EHP 1.10x + wolf-pack Life/Armour — retire …
ackness Jul 17, 2026
a208a17
docs: record backlog sweep #7 outcomes in adapting-to-0.5.4b Remaining
ackness Jul 17, 2026
55f4c25
Merge branch 'worktree-agent-aa2e09a93bbb2938b' into v0.0.3-dev
ackness Jul 17, 2026
41f3b71
fix(parity): allocate named jewel sockets granted via anoint (Zarokh'…
ackness Jul 17, 2026
324e08e
docs: record #8 outcome in adapting-to-0.5.4b (named-socket anoint ro…
ackness Jul 17, 2026
c7e74c2
data(parser): restore vendor 'skill speed' three-name fan-out
ackness Jul 17, 2026
a3bc394
feat(core): warcry uptime machine - Infernal Cry gain-as-fire (backlo…
ackness Jul 17, 2026
0ad6918
test(parity): record warcry-uptime gains - dot @10% baseline 31->32
ackness Jul 17, 2026
0ab6c8d
Merge branch 'worktree-agent-a058573feaee01529' into v0.0.3-dev
ackness Jul 17, 2026
3d0613b
test: align charm guard expectation and coverage baseline with #7 de-…
ackness Jul 17, 2026
df73354
fix(build): route meta-gem support halves into group support judgement
ackness Jul 17, 2026
b0eaadd
test(parity): MARTIAL ES 1.12x is a stale 0.1-era embedded golden, no…
ackness Jul 17, 2026
57f703e
fix(special): Point Blank distance-ramp MORE damage via curated entries
ackness Jul 17, 2026
d9e174c
feat(offence): Barrage repeats DPS MORE channel
ackness Jul 17, 2026
73c0834
fix(items): drop bare typed weapon adds when the weapon is not the so…
ackness Jul 17, 2026
0c67f2a
test(parity): ratchet off/dot baselines after #10; debug aids
ackness Jul 17, 2026
98ef99e
docs: record #10 offence-residual closures in the 0.5.4b ledger
ackness Jul 17, 2026
9fe3bb0
Merge branch 'worktree-agent-a31cbc6a9ddf3977a' into v0.0.3-dev
ackness Jul 17, 2026
fe87c98
fix(minion): scale summons off the ally life table at effective gem l…
ackness Jul 17, 2026
20db1e2
feat(statmap): minion-domain mapper + companion mitigation buff allow…
ackness Jul 17, 2026
20bfcd5
feat(companion): ally-mitigation defence layer into EHP/max-hit (#12)
ackness Jul 17, 2026
699e9e3
fix(defence): round armour DR to integer pct in taken-hit chain (vend…
ackness Jul 18, 2026
8b742d8
feat(pools): apply Life/Mana ConvertTo-defence deduction to pool values
ackness Jul 18, 2026
fff5b2e
fix(reservation): fold Blasphemy per-curse flat into base before sing…
ackness Jul 18, 2026
2896807
feat(quality): altQualityStats channel gated on GemlingQuality flag
ackness Jul 18, 2026
1d2ba56
fix(defence): model enemy Intimidated base pair behind presence condi…
ackness Jul 18, 2026
8bf4f3d
feat(item): The Adorned corrupted-magic-jewel effect scaling
ackness Jul 18, 2026
120f0f5
fix(parity): recompute item armour/evasion from base DB like ES
ackness Jul 18, 2026
8c7b39b
chore(oracle): enemy dealt-damage tabulate + ORACLE_DUMP_ITEMS item dump
ackness Jul 18, 2026
af1c9a3
test(parity): ratchet defensive baselines for #13 residual fixes
ackness Jul 18, 2026
2d6f169
test: pin minion life to the ally table semantics from #12
ackness Jul 18, 2026
22e1b79
feat(defence): Smith connected-notable multiplier + item attribute-re…
ackness Jul 18, 2026
3ab51dc
fix(ehp): average block over all four vendor categories
ackness Jul 18, 2026
0cd02b0
test(parity): raise defence baselines after #14 long-tail triage
ackness Jul 18, 2026
6e78f2d
docs: record #14 defensive long-tail triage table and fixes
ackness Jul 18, 2026
8b72517
Merge branch 'worktree-agent-a08ce609ab3f24a4a' into v0.0.3-dev
ackness Jul 18, 2026
bb4b220
fix(tree): radius-jewel grants no longer land on inactive weapon-set …
ackness Jul 18, 2026
14cecb6
fix(calc): honor non-damage main skill in designated group; untyped s…
ackness Jul 18, 2026
77ed735
test(parity): raise baselines to full score (off 80/80, dot 37/37); r…
ackness Jul 18, 2026
ce4028a
test(wasm): stage overlay-common in memory backend; align guard tests…
ackness Jul 18, 2026
ba0b979
fix(desktop): add corrupted field to example Item initializer (#13 fa…
ackness Jul 18, 2026
85d1b09
chore(release): bump workspace version to 0.0.3
ackness Jul 18, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Tool-generated artifacts: keep them committed (runtime/deploy needs them),
# but collapse them in diffs/PR review and language stats.
data/**/generated/** linguist-generated -diff
data/**/overlay/** linguist-generated
# Hand-curated overlay entries must stay reviewable.
data/**/overlay/special_mods.json -linguist-generated diff
examples/demo-bd-test/builds/*/meta.json linguist-generated -diff
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
/target-gate/
/target-master/
/target-dualrun/
# vendor-delta 报告的 codeload tarball 缓存(pipeline/diff-vendor-calcs.sh)
/.cache/

# 本机相关的 cargo 配置(网络卷开发时 target-dir 重定向到本地盘)
/.cargo/config.toml
Expand Down
30 changes: 15 additions & 15 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ members = [
resolver = "2"

[workspace.package]
version = "0.0.2"
version = "0.0.3"
edition = "2024"

[workspace.dependencies]
Expand Down
4 changes: 4 additions & 0 deletions apps/pobr-cli/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -584,6 +584,10 @@ fn explain_tag(tag: &ModTag) -> TagExplain {
kind: "SkillTypes".to_string(),
detail: format!("限技能类型 {st:?}"),
},
ModTag::SkillTypesNeg(st) => TagExplain {
kind: "SkillTypesNeg".to_string(),
detail: format!("排除技能类型 {st:?}"),
},
ModTag::SkillName { names } => TagExplain {
kind: "SkillName".to_string(),
detail: format!("仅当主技能是 `{}` 时生效", names.join("` / `")),
Expand Down
1 change: 1 addition & 0 deletions apps/pobr-desktop/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ pub fn example_build() -> Build {
base: ItemBaseId::from("Iron Ring"),
rarity: ItemRarity::Rare,
quality: 0,
corrupted: false,
implicit_texts: vec![],
modifier_texts: vec![
"+25 to maximum Life".to_string(),
Expand Down
1 change: 1 addition & 0 deletions apps/pobr-wasm/src/build_api/analysis.rs
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,7 @@ fn apply_variant(
gem_level: gem.level,
quality: gem.quality,
stat_set_index: None,
name_spec: None,
});
if let Some(effect) = data.gem_effects.get(&gem.skill_id) {
group.gem_ids.push(effect.gem_id.clone());
Expand Down
1 change: 1 addition & 0 deletions apps/pobr-wasm/src/build_api/request.rs
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,7 @@ fn socket_group_from_input(input: &SocketGroupInput, data: &BuildData) -> Socket
gem_level: gem.level,
quality: gem.quality,
stat_set_index: None,
name_spec: None,
});
if let Some(gem_id) = gem_id {
group.gem_ids.push(gem_id);
Expand Down
35 changes: 22 additions & 13 deletions apps/pobr-wasm/tests/contract_golden.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1135,21 +1135,30 @@ fn memory_backend_matches_dir_backend() {
let request = serde_json::json!({ "pob_code": demo_code() }).to_string();
let from_dir = pobr_wasm::calculate_build_json(&request).expect("dir backend");

// 把版本目录整体读入内存表,走 stage/init 路径重建。
// 把版本目录整体读入内存表,走 stage/init 路径重建。版本无关策展层
// `data/overlay-common/`(P1-3)位于版本目录的兄弟路径,内存后端按
// `overlay-common/<rel>` 键解析(见 `pobr-gamedata::paths::overlay_common_path`),
// 生产 wasm 流程(web sync-data)同样打包该目录——staging 必须一并灌入,
// 否则内存后端静默丢失全部 curated special_mods。
let root = repo_data_root().join(pobr_data::GOLDEN_PARITY_DATA_VERSION);
for entry in walk_files(&root) {
// GameData 只读 JSON;跳过杂项文件(.DS_Store 等)。
if entry.extension().and_then(|e| e.to_str()) != Some("json") {
continue;
let common_root = repo_data_root().join("overlay-common");
let stage_tree = |tree_root: &std::path::Path, key_prefix: &str| {
for entry in walk_files(tree_root) {
// GameData 只读 JSON;跳过杂项文件(.DS_Store 等)。
if entry.extension().and_then(|e| e.to_str()) != Some("json") {
continue;
}
let rel = entry
.strip_prefix(tree_root)
.unwrap()
.to_string_lossy()
.replace('\\', "/");
let content = std::fs::read_to_string(&entry).expect("read data file");
pobr_wasm::stage_data_file(&format!("{key_prefix}{rel}"), &content);
}
let rel = entry
.strip_prefix(&root)
.unwrap()
.to_string_lossy()
.replace('\\', "/");
let content = std::fs::read_to_string(&entry).expect("read data file");
pobr_wasm::stage_data_file(&rel, &content);
}
};
stage_tree(&root, "");
stage_tree(&common_root, "overlay-common/");
pobr_wasm::init_staged_data().expect("init memory backend");
let from_memory = pobr_wasm::calculate_build_json(&request).expect("memory backend");
assert_eq!(
Expand Down
9 changes: 7 additions & 2 deletions apps/pobr-wasm/tests/tier_lines.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,11 +46,16 @@ fn current_data_annotates_explicit_tiers() {
}

/// 优雅降级:无 tier 池字段(group/spawn_weights)的数据包不标 tier。
/// 显式钉 4.5.0.3.4——它早于 tier 数据通道,缺池字段;golden 版(4.5.4.3 起)
/// 已含池数据会标 tier,故此降级用例不能再借 `GOLDEN_PARITY_DATA_VERSION`。
/// 显式钉 4.5.0.3.4——这是「早于 tier 数据通道的旧格式包」的 fixture 钉(非数据
/// 内容计数钉,不进 test_pins 快照);golden 版(4.5.4.3 起)已含池数据会标
/// tier,故此降级用例不能借 `GOLDEN_PARITY_DATA_VERSION`。旧包被清理时跳过。
#[test]
fn golden_data_without_pool_fields_omits_tiers() {
let dir = repo_data_root().join("4.5.0.3.4");
if !dir.is_dir() {
eprintln!("SKIP: 旧格式 fixture 数据包 4.5.0.3.4 不在仓库(已清理)");
return;
}
let lines = classify(dir.to_str().unwrap());
assert!(
lines.iter().all(|l| l.get("tier").is_none()),
Expand Down
27 changes: 19 additions & 8 deletions apps/pobr-wasm/tests/unsupported_specials.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
//! 药剂/护符使用效果类词条经 special 表解析为正确机制语义,不再进未支持报表:
//! 免疫 → *Immune flag、Guard → GuardAbsorbRate/Limit(承受层真实吸收)、
//! 瞬时回魔/魔力溢出/附身 → 结构化 mod 登记(vendor 对照与来源见 overlay source_note)。
//! 免疫 → *Immune flag、瞬时回魔/魔力溢出/附身 → 结构化 mod 登记(vendor 对照
//! 与来源见 overlay source_note)。
//!
//! 例外:`Also grants N Guard` 曾被策展条目 also_grants_guard 建模为承受层吸收,
//! 但 vendor ModParser 根本不解析它——对 PoB2 golden 是幻影 Guard 池(存量 #7
//! 摘除,ritualist EHP 1.10x→1.00x)。与 PoB2 对齐后它回到「未建模 → 响亮进
//! unsupported 报表、不影响 hit pool」的口径。

use pobr_gamedata::repo_data_root;
use serde_json::{Value, json};
Expand Down Expand Up @@ -53,27 +58,33 @@ fn charm_flask_use_effect_lines_are_recognized() {
"Recover 295 Mana when Used",
"Mana Recovery from Flasks can Overflow maximum Mana during Effect",
"Possessed by Spirit Of The Stag for 19 seconds on use",
"Also grants 481 Guard",
] {
assert!(
!unsupported.iter().any(|u| u.contains(line)),
"`{line}` 仍在未支持列表: {unsupported:?}"
);
}
// guard 行未建模(vendor 同样不解析)——必须响亮上报而非静默丢弃。
assert!(
unsupported
.iter()
.any(|u| u.contains("Also grants 481 Guard")),
"`Also grants 481 Guard` 应进未支持列表(#7 摘除幻影建模后与 PoB2 口径一致): {unsupported:?}"
);
}

#[test]
fn guard_line_extends_hit_pool() {
fn guard_line_does_not_extend_hit_pool() {
let dir = repo_data_root().join(pobr_gamedata::data_version());
pobr_wasm::init_data_from_dir(dir.to_str().unwrap()).expect("init data");

let without = calculate(false);
let with = calculate(true);
// Guard 是生命/ES 前的全额吸收池(agent-docs/active-defences.md §2):
// 物理 max hit 应至少提高 Guard 池大小(481)。
// #7 摘除 also_grants_guard 幻影建模后,guard 行不得再扩大 hit pool
// (vendor 不解析该行;此前的 +481 是 PoBR 单方面多建模的幻影池)。
let delta = stat(&with, "PhysicalMaxHit") - stat(&without, "PhysicalMaxHit");
assert!(
delta >= 481.0,
"Guard 481 应扩大物理 max hit(实际增量 {delta})"
delta.abs() < 1.0,
"guard 行不应改变物理 max hit(实际增量 {delta})"
);
}
30 changes: 30 additions & 0 deletions crates/pobr-build/examples/dump_components.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,36 @@ fn main() {
out.action_rate,
out.hit_chance
);
// POBR_DUMP_DEFENCE=1:附加防御/EHP 池分解(与 oracle mainOutput 的
// <Type>TotalHitPool / LifeRecoverable / MaximumHitTaken 族对照)。
if std::env::var("POBR_DUMP_DEFENCE").is_ok() {
println!(
" life={:.2} life_unres={:.2} life_recoverable={:.2} es={:.2} es_cap={:.2} ward={:.2} mana={:.2} mana_unres={:.2}",
out.life,
out.life_unreserved,
out.life_recoverable,
out.energy_shield,
out.energy_shield_recovery_cap,
out.ward,
out.mana,
out.mana_unreserved,
);
for (i, m) in out.minions.iter().enumerate() {
println!(
" minion[{i}]: level={} life={:.2} armour={:.2} evasion={:.2} es={:.2}",
m.level, m.life, m.armour, m.evasion, m.energy_shield,
);
}
println!(
" maxhit: phys={:.1} fire={:.1} cold={:.1} light={:.1} chaos={:.1} total_ehp={:.1}",
out.physical_max_hit_pob2,
out.fire_max_hit_pob2,
out.cold_max_hit_pob2,
out.lightning_max_hit_pob2,
out.chaos_max_hit_pob2,
out.total_ehp_pob2,
);
}
let mut sum = 0.0;
for c in &out.damage_components {
let avg = c.avg();
Expand Down
Loading