From ad6ea9ad7e06ce9838203f293db6d09f05e02720 Mon Sep 17 00:00:00 2001 From: shenlei Date: Tue, 22 Sep 2026 17:12:16 +0900 Subject: [PATCH] skill: switch 40250 parity skill to file-by-file 1:1 porting Unit of work is a 40250 source unit; current-only logic is a defect; unreachable code is not evidence. Adds per-function port-map schema, priority by player-visible gameplay, parallel worktree rules, and a corrected project map. Co-Authored-By: Claude Opus 5 --- .../skills/metin2-40250-parity-audit/SKILL.md | 181 ++++++++++-------- .../references/audit-schema.md | 40 +++- .../references/project-map.md | 89 +++++---- .../skills/metin2-40250-parity-audit/SKILL.md | 2 +- 4 files changed, 189 insertions(+), 123 deletions(-) diff --git a/.agents/skills/metin2-40250-parity-audit/SKILL.md b/.agents/skills/metin2-40250-parity-audit/SKILL.md index a1fdc44b..0ab659fa 100644 --- a/.agents/skills/metin2-40250-parity-audit/SKILL.md +++ b/.agents/skills/metin2-40250-parity-audit/SKILL.md @@ -1,115 +1,126 @@ --- name: metin2-40250-parity-audit -description: Audit, implement, fix, or verify behavioral parity between the Metin2 40250 Windows C++ client and this Godot client. Use whenever a request mentions 40250 comparison, 1:1 parity, missing original-client behavior, parity regressions, or continuing the client audit. Do not use for unrelated features that have no 40250 compatibility requirement. +description: Port, fix, or verify 1:1 parity between the Metin2 40250 Windows C++ client and this Godot client. Use for any 40250 comparison, 1:1 parity, missing original-client behavior, parity regression, or continuation of the client port/audit. Work is done by transliterating 40250 source units, not by hunting behavior differences. --- -# Metin2 40250 parity audit +# Metin2 40250 1:1 port -Treat the reachable 40250 implementation semantics and its observable behavior as the reference contract. The Godot architecture and APIs may differ, but its gameplay algorithms, branch conditions, state-transition order, constants, units, timing/event sources, resource/data sources, protocol side effects, and failure/cleanup behavior must not differ unless the difference is a documented platform adapter with evidence of semantic equivalence. Compare complete call chains, not filenames or similarly named functions. +## Principle -## Persistent state +metin2-client is the cross-platform build of the 40250 Windows client. Apart from rendering and +platform APIs, every gameplay algorithm, branch, constant, state order, timing source, data +source, protocol side effect and cleanup path must be the 40250 one. -The audit ledger is the source of truth: +The 40250 source is the specification. Do not design behavior; transcribe it. Consequences: -- `audit/manifest.json`: current contract states and evidence links. -- `audit/history.jsonl`: append-only state-change history. -- `audit/contracts/`: detailed evidence for individual contracts. -- `audit/reports/`: generated summaries; never treat these as the source of truth. -- `audit/remediation-roadmap.md`: current repair order, anti-repeat rules, and the next primary contract. +- **The unit of work is a 40250 source unit** (one `.cpp` file, or one cohesive function group in a + very large file such as `PythonNetworkStreamPhaseGame.cpp`), not a behavior branch. A round reads + the whole unit and fixes every divergence in it. +- **Current-client logic with no 40250 counterpart is a defect**, not an adaptation: delete it + (e.g. an invented `clampf(0.25, 3.0)` on move speed, a periodic idle `FUNC_WAIT` resend, a + client-side boss AI). "The reference has no mechanism for X, so we added one" is never a + platform adaptation. +- **Unreachable code is not an implementation, and tests of it are not evidence.** Code that the + runtime never loads (e.g. a `*_system.gd` referenced only by its own `test_*_parity.gd`) must be + deleted or wired in by porting the real 40250 caller, never cited as parity. -Before auditing, fixing, or claiming parity: +## Porting target per layer -1. Run `python3 .agents/skills/metin2-40250-parity-audit/scripts/audit_ledger.py refresh --write`. -2. Run `python3 .agents/skills/metin2-40250-parity-audit/scripts/audit_ledger.py report`. -3. Read the relevant existing contract and tests. Do not repeat a still-valid `TEST_VERIFIED` audit unless the user explicitly requests revalidation. -4. If no contract exists, add one with a stable behavior ID before marking work complete. +| 40250 layer | How to port | Where | +| --- | --- | --- | +| Platform-independent C++ logic (packet structs/handlers, sequence table, formulas, state machines in `UserInterface/`, `GameLib/`; `EterPack`, `EterLocale`) | Transliterate C++ -> C++, keeping class/function structure and names so each function has one counterpart | `extension/src/` | +| 40250 C++ logic that currently lives in GDScript | Port function by function, same names in snake_case, same order of statements | existing `.gd` owner | +| Python UI (`assets/root/*.py`, `uiscript/`) | Translate per `.py` file into its GDScript window, keeping method structure | `project/ui/` | +| Direct3D, Granny, Miles, Win32 input/window, IME, DirectX math | Platform adapter; equivalence by observable output | `extension/`, `project/` | -Before selecting the next repair target, read `audit/remediation-roadmap.md` and the -latest relevant history entries. Select by the documented priority and end-to-end -user flow, not by whichever local difference is easiest to patch. A contract may not -be used to repeat an already completed issue or branch. Every round must select an -explicit issue/branch ID using the roadmap's stable format and compare it with -`audit/history.jsonl` before editing. Older contract-level history entries do not -prove that every branch in that contract is complete; create the branch-level ID -when first selecting it. -The same issue/branch ID may be revisited only for a new regression, a substantive -implementation change, or new evidence that invalidates the earlier conclusion. -The same contract may be selected in a later round when a different `remaining` -branch is selected; contract IDs group behavior and are not deduplication keys. A -`PARTIAL` contract is not permission to repeat already verified work. +Mark every ported function with a one-line tag at its definition so coverage can be scanned +mechanically: `// 40250: CInstanceBase::SetMoveSpeed` (C++) or `# 40250: CInstanceBase::SetMoveSpeed` +(GDScript). Tag only real counterparts. -Read [references/audit-schema.md](references/audit-schema.md) whenever creating or changing ledger entries. Read [references/project-map.md](references/project-map.md) when locating reference code, current implementation, existing gap documents, or test runners. +## Round workflow -## Full-client inventory gate +1. **Pick a unit** from the queue in `audit/remediation-roadmap.md` (ordered by user-visible + gameplay; see Priority). Skip units whose port-map entries are all `PORTED`/`ADAPTED`/`N_A` and + whose reference hash is unchanged. +2. **Read the whole reference unit** under the reference root (see `references/project-map.md`; + use `grep -a`, many files contain CP949 bytes). Read every current counterpart, found by the + `40250:` tags, the port-map entry, or `references/project-map.md`. +3. **For each reference function**, compare statement by statement: preconditions and early + returns, branches, formulas, constants and units, state writes and their order, timing/event + source, data source (proto/msa/msm/txt, never hardcoded), packets sent, cleanup. Then: + - transliterate it where missing or divergent; + - delete current-only logic it replaces; + - mark `N_A` only for pure platform plumbing (D3D state, Python binding glue, Win32), with a reason. +4. **Test what changed**: a focused test using the reference's own boundary values for each changed + formula/branch (fails before, passes after). Do not write tests for unchanged or trivial code. + Run only the tests touching the changed files; the full suite runs once per batch. +5. **Record**: update the unit's port-map entry (per-function status) and append one line to + `audit/history.jsonl`. Touch `audit/manifest.json` and `audit/contracts/*.md` only when a + contract's status changes. Do not write narrative into `remediation-roadmap.md`; only reorder or + tick the queue. +6. **Commit** the unit (code + test + port-map) as one commit. -This skill covers the complete reachable 40250 client behavior surface, not only the first few reported bugs. Before claiming the audit is broadly complete: +A round that finds no divergence still records the per-function result so the unit is never re-read +without a hash change. -1. Inventory active 40250 runtime areas across `UserInterface`, `GameLib`, `EffectLib`, `EterLib`, `EterGrnLib`, `PRTerrainLib`, `MilesLib`, `EterPack`, and `EterLocale`, then map each externally meaningful behavior to `project/`, `extension/`, `formats/`, resources, and tests. -2. Keep one stable contract ID per externally meaningful behavior, not one per source file. Group helper files under the behavior they implement, but do not omit a reachable behavior because its implementation is spread across several libraries. -3. Put every mapped behavior in `audit/manifest.json`, including behaviors not yet checked. Use `UNMAPPED` when no current implementation or reference mapping is established, `MAPPED` when both entry points are located, and `PARTIAL` when a material gap is known. -4. Record current-client-only features as `EXCLUDED` only with an explicit reason that they have no 40250 counterpart and are outside the parity target. Never silently omit them from the inventory. -5. The inventory is incomplete while any active runtime area has no contract entry. A clean test suite or a high percentage of mapped files does not waive this gate. +## Port-map (dedup and coverage) -## Audit method +`audit/port-map//.json`, one file per reference source unit (per-file to avoid merge +conflicts between parallel rounds). Schema in `references/audit-schema.md`. Function statuses: -For each behavior: +- `TODO` — not yet compared. +- `PORTED` — current counterpart is statement-equivalent; `impl` names it. +- `ADAPTED` — platform adapter; `note` states both sides and the invariant, with a test. +- `N_A` — platform plumbing with no gameplay semantics; `note` states why. +- `DIVERGENT` — known different and not yet fixed; `note` says how. +- `NEEDS_LIVE` — code ported, but equivalence depends on real-server/Windows evidence. -1. Define the external trigger, preconditions, state transitions, outputs, timing, interruption, failure, and cleanup behavior. -2. Trace the complete reachable 40250 call chain, including resource-driven branches and compile-time feature flags. -3. Build a branch-by-branch equivalence table mapping the reference preconditions, decisions, formulas, state writes, ordering, timing sources, resource reads, outputs, and cleanup paths to the current native extension, GDScript, resources, protocol handling, and UI. -4. Classify every difference as missing, partial, wrong order, wrong value/unit, wrong algorithm, wrong timing/event source, wrong resource/data source, duplicate, platform adapter, or intentionally excluded. -5. Treat automated output equality as necessary but not sufficient: tests can miss branches, so a different algorithm cannot be approved merely because sampled outputs currently match. -6. Fix root mechanisms rather than coordinates, entity IDs, individual assets, one-off timing constants, or simplified approximations. -7. Add or strengthen an automated test that fails before the fix and covers the reference behavior. Include boundary, rejection, interruption, and cleanup paths when they materially affect the behavior. -8. Run the narrow test first, then related subsystem tests, then `git diff --check`. -9. Update the contract's implementation-equivalence matrix, manifest, fingerprints, and history in the same change. Never mark `STATIC_VERIFIED` or `TEST_VERIFIED` without complete equivalence evidence. +A function is revisited only if its reference or implementation hash changed or new evidence +contradicts its status. This replaces the old per-branch "do not repeat" prose. -For classic network phase audits, run `scripts/audit_packet_registry.py` together -with `scripts/audit_phase_dispatch.py`. The former compares registered wire -header values and static/dynamic kinds; the latter compares Login/Select/Loading/ -Game phase branches by numeric value while explicitly reporting transport-control -and observer-stream exclusions. A PASS from either script is structural evidence, -not proof that handler side effects are equivalent. +## Priority -## Implementation-equivalence gate +Order the queue by what a player sees, P0 first: -Source text and engine-facing APIs do not need to be identical, but the implementation must be semantically unified with 40250. Before verification, prove all of these independently: +1. Actor/movement: `InstanceBase*.cpp`, `GameLib/ActorInstance*.cpp`, `PythonPlayer*.cpp`, + `PythonPlayerEventHandler.cpp`, `PythonCharacterManager*.cpp`. +2. Combat/skill: `ActorInstanceBattle.cpp`, `ActorInstanceAttach*`, `FlyingObject*`, + `PythonPlayerSkill.cpp`, `PythonSkill.cpp`. +3. Game-phase packet handlers: `PythonNetworkStreamPhaseGame*.cpp`, `PythonNetworkStreamEvent.cpp`. +4. Items/inventory/UI data: `PythonItem.cpp`, `PythonExchange.cpp`, `PythonSafeBox.cpp`, `PythonShop.cpp`, + then the Python UI scripts. +5. World/map/terrain/effects, then audio, weather, platform. -- identical effective preconditions and early-return rules; -- identical reachable branch structure and branch outcomes; -- equivalent algorithms and formulas, without simplified substitutes; -- identical state mutations and mutation order; -- identical constants, tolerances, coordinate conversions, and units after explicit platform conversion; -- identical timing authority and event source, such as `.msa` events rather than replacement timers; -- identical resource, table, and protocol data authority rather than hardcoded substitutes; -- identical network and externally visible side effects and their ordering; -- identical interruption, rejection, rollback, failure, and cleanup behavior. +Login/phase edge cases whose only open item is real-server evidence are `NEEDS_LIVE` and go to a +separate live-verification batch; do not spend porting rounds on them. -Permitted differences are limited to documented platform adapters such as C++ containers to Godot collections, DirectX matrices to `Transform3D`, or Windows input APIs to Godot input APIs. For every adapter, document both sides, the conversion invariant, and a focused equivalence test. If any material item differs or lacks proof, status must remain `PARTIAL` or `MAPPED`. +## Parallel rounds -## Evidence rules +Independent units may run in parallel, one git worktree per unit. Two parallel rounds must not +edit the same implementation file; if a unit's counterpart overlaps a running round, queue it. +Port-map files are per unit and `history.jsonl` is append-only, so merges are mechanical. -- `MAPPED` means only that both sides were located. -- `STATIC_VERIFIED` requires a documented call-chain and implementation-equivalence matrix covering every material branch. Similar output alone is insufficient. -- `TEST_VERIFIED` additionally requires meaningful automated behavior tests with a recorded passing result; tests do not waive the implementation-equivalence gate. -- Engine/platform replacement may be `EXCLUDED` only when the replacement and externally observable verification are documented. -- A source or test fingerprint change makes prior verification `STALE`; investigate only the affected contracts. -- Existing prose in `docs/CLIENT-GAP.md` and similar documents is useful evidence, but it is not a current verification state unless represented in the ledger. -- Do not claim that code inspection proves visual, timing, input-feel, driver, or Windows-specific parity. Record those limits explicitly. +## Contracts and verification states -## Scope and safety +`audit/manifest.json` contracts remain the behavior-level roll-up (status meanings and gates in +`references/audit-schema.md`). A contract may reach `STATIC_VERIFIED` only when every reference +unit it lists has no `TODO`/`DIVERGENT` functions, and `TEST_VERIFIED` when its tests also pass. +Never cite a test of unreachable code, and never mark visual, timing-feel, driver or Windows-only +behavior verified from code inspection alone. -- Preserve unrelated dirty-worktree changes. -- Prefer the active files from the 40250 Visual Studio build; do not audit disabled, third-party, or obsolete code as product behavior without evidence that it is reachable. -- Keep credentials, live-server data, copyrighted binary dependencies, generated captures, and local run outputs out of the ledger. -- Do not change live servers or external systems unless the user requested it. +## Tools + +- `scripts/audit_ledger.py refresh --write | report --write | validate` — run once per batch, not + per round. Missing reference files are an error, not a silent fingerprint. +- `scripts/audit_packet_registry.py`, `audit_phase_dispatch.py`, `audit_sequence_table.py` — run + when a round touches `extension/src/net/`. +- `scripts/audit_source_coverage.py` — maps active 40250 sources (from the `.vcxproj` files) to + contracts. +- Reference root: `MT_40250_SOURCE` env var, else `reference_root` in `audit/manifest.json` + (relative to the repo root). ## Completion report -Report the contract IDs changed, reference and implementation call chains, discrepancies fixed, tests run, remaining unverified branches, and resulting ledger status. A subsystem is complete only when its in-scope contracts have no unexplained `UNMAPPED`, `PARTIAL`, `STALE`, or `REGRESSION` entries. - -Also report whether the round followed `audit/remediation-roadmap.md`, the selected -issue/branch ID, why it was not already completed in `audit/history.jsonl`, and the -next priority candidate. Do not claim that a single subsystem is complete merely -because its focused tests pass while its ledger contract still has material -`remaining` branches. +Per round: unit, functions ported/fixed/deleted/marked `N_A`, divergences found (one line each: +reference vs old current behavior), tests run, commit hash, remaining `TODO`/`DIVERGENT`/`NEEDS_LIVE` +in the unit. Keep it short. diff --git a/.agents/skills/metin2-40250-parity-audit/references/audit-schema.md b/.agents/skills/metin2-40250-parity-audit/references/audit-schema.md index ceda07da..146af97e 100644 --- a/.agents/skills/metin2-40250-parity-audit/references/audit-schema.md +++ b/.agents/skills/metin2-40250-parity-audit/references/audit-schema.md @@ -97,12 +97,46 @@ An adaptation may change APIs or representation, never gameplay rules, branch ou When a verified entry becomes stale, retain its previous evidence and history. Do not delete the entry or recreate it under a new ID. -## History events +A contract's `evidence.tests` and `implementation.files` must be reachable from the runtime +(loaded by `AppFlow`/`GameScene`/the native extension in a normal session). A file used only by its +own test is not an implementation and its test is not evidence. -Append one compact JSON object per meaningful state change to `audit/history.jsonl`: +## Port-map entries + +One JSON file per 40250 source unit at `audit/port-map//.json`: ```json -{"time":"2026-09-19T00:00:00Z","event":"status_changed","id":"combat.local.normal_attack","from":"MAPPED","to":"TEST_VERIFIED","reason":"call chain audited and tests passed"} +{ + "reference": "UserInterface/InstanceBaseMovement.cpp", + "reference_sha256": "", + "priority": "P0", + "contracts": ["movement.keyboard.motion", "movement.remote_sync_state"], + "functions": { + "CInstanceBase::SetMoveSpeed": { + "status": "PORTED", + "impl": ["project/player_controller.gd:set_server_speed", "extension/src/net/entity_store.cpp:motion_move_speed"], + "note": "" + }, + "CInstanceBase::__EnableSkipCollision": {"status": "TODO"} + } +} ``` +- Function keys are the reference's qualified names (`Class::Method`, or the free-function name). +- `status` is one of `TODO`, `PORTED`, `ADAPTED`, `N_A`, `DIVERGENT`, `NEEDS_LIVE` (meanings in `SKILL.md`). +- `impl` is required for `PORTED`/`ADAPTED`/`NEEDS_LIVE`; `note` is required for `ADAPTED`, `N_A`, + `DIVERGENT` and `NEEDS_LIVE`. `ADAPTED` also needs a `test` path. +- When `reference_sha256` no longer matches the file, every non-`TODO` function in the unit must be + rechecked before the hash is updated. + +## History events + +Append one compact JSON line per round to `audit/history.jsonl`: + +```json +{"time":"2026-09-22T00:00:00Z","event":"port_round","unit":"UserInterface/InstanceBaseMovement.cpp","ported":["CInstanceBase::SetMoveSpeed"],"deleted":["player_controller.gd clampf(0.25,3.0)"],"divergent":[],"needs_live":[],"tests":["project/keyboard_motion_timeline_test.gd PASS"],"commit":"c5c183da"} +``` + +Contract status changes still use `{"event":"status_changed","id":...,"from":...,"to":...,"reason":...}`. + Never store credentials, packet payload secrets, binary captures, or generated screenshots in the ledger. diff --git a/.agents/skills/metin2-40250-parity-audit/references/project-map.md b/.agents/skills/metin2-40250-parity-audit/references/project-map.md index 62a893e1..e23df617 100644 --- a/.agents/skills/metin2-40250-parity-audit/references/project-map.md +++ b/.agents/skills/metin2-40250-parity-audit/references/project-map.md @@ -1,49 +1,70 @@ # Project map -## Reference client +## Reference client (40250) -- Root: `../40250/Server Client TMP4/ClientVS22/source` -- High-level game and packet flow: `UserInterface` -- actors, motion, maps, flying objects: `GameLib` -- rendering, input, collision primitives: `EterLib` -- effects: `EffectLib` -- Granny integration: `EterGrnLib` -- audio: `MilesLib` -- terrain: `PRTerrainLib` +- Root: `MT_40250_SOURCE`, else `reference_root` in `audit/manifest.json` — on this machine + `../40250/Server Client TMP4/ClientVS22/source` relative to the repo (quote it: the path has spaces). +- Active sources: the `ClCompile`/`ClInclude` items in `../vs_files/*/*.vcxproj`; files not listed + there are not product code. +- Many `UserInterface/` files contain CP949 bytes in comments: use `grep -a` / `grep -arn`, or plain + grep silently reports no match. +- Python UI and game scripts are **not** in the source tree: they are in this repo at + `assets/root/*.py` (e.g. `uitarget.py`, `uitaskbar.py`) and `assets/uiscript/`. +- Server source (for protocol questions only, not client behavior): `../40250/Server Client TMP4/Server`. -Use the Visual Studio project and active preprocessor flags to distinguish reachable product code from disabled, obsolete, and third-party code. +| Library | Lines | Content | +| --- | ---: | --- | +| `UserInterface` | 64.7k | network stream + phases, `CPythonPlayer`, `CInstanceBase`, managers, Python modules | +| `EterLib` | 48.7k | device/render state, camera, input/IME, net stream, resources, collision primitives | +| `GameLib` | 30.7k | `CActorInstance` (motion, battle, attach, events), flying objects, map/terrain, race data | +| `EterBase` | 6.3k | utilities, timer, CRC, file | +| `EffectLib` | 6.1k | effect/particle instances | +| `EterGrnLib` | 5.9k | Granny models, motion, LOD | +| `EterPack` | 3.4k | pack format | +| `MilesLib` | 2.3k | audio | +| `EterLocale` | 1.1k | codepages, locale strings | +| `PRTerrainLib` | 1.0k | terrain texture/height data | ## Current client -- GDScript runtime and tests: `project/` -- native extension: `extension/` -- format readers: `formats/` -- shared/native libraries: `libgr2/` -- extracted assets and tables: `assets/` -- numerical reference oracle: `oracle/` -- host-side tools: `tools/` +- GDScript runtime: `project/` (entry `project/app_flow.gd`, world `project/game_scene.gd`); UI in `project/ui/`. +- Native extension: `extension/src/` (network in `extension/src/net/`, classic 40250 protocol in `extension/src/net/classic/`). +- Format readers: `formats/`; Granny: `libgr2/`; assets/tables: `assets/`; Granny oracle: `oracle/`; tools: `tools/`. -## Existing evidence +### Known counterparts -- `docs/CLIENT-GAP.md`: historical broad gap analysis; migrate useful claims into contracts rather than trusting status text. -- `docs/CLIENT-PARITY-AUDIT-AND-FIX-GUIDE.md`: existing methodology and high-risk domains. -- `docs/CLIENT-40250-PORT.md`: porting context. -- `docs/PARITY-GAP.md`: visual/rendering gap notes. +| 40250 | Current | +| --- | --- | +| `CPythonNetworkStream*` phases, `CAccountConnector` | `extension/src/net/classic/classic_session.cpp`, `classic_stream.cpp`, `classic_parser.cpp` | +| packet structs / `CMainPacketHeaderMap` | `extension/src/net/classic/wire_classic.h` | +| `EterLib/NetStream.cpp` sequence + cipher | `extension/src/net/classic/sequence_table.h`, `classic_cipher.cpp` | +| `CPythonCharacterManager`, `CInstanceBase` state from packets | `extension/src/net/entity_store.cpp`, `project/net_world.gd` | +| `CPythonPlayer` input/move (`PythonPlayerInput*.cpp`), main `CInstanceBase` movement | `project/player_controller.gd` | +| `PythonPlayerEventHandler.cpp` (OnMove/OnMoving/OnWaiting/OnStop -> `SendCharacterStatePacket`) | `project/net_play.gd` | +| `CPythonPlayer` skill use | `project/player_skill.gd` | +| `CFlyingObject*` | `project/fly_object.gd` | +| `EterLib/Camera.cpp` + `PythonApplicationCamera` | `project/game_camera.gd` | +| `ui*.py` windows | `project/ui/*_ui.gd` | + +### Code that is not a counterpart + +About 100 of the 111 `project/*_system.gd` files are loaded only by their own +`project/test_*_parity.gd` (never by the runtime). They are not implementations of 40250 +behavior and their tests are not evidence; delete them, or replace them by porting the real 40250 +code path when that path exists. + +## Existing evidence (historical) + +- `docs/CLIENT-GAP.md`, `docs/CLIENT-PARITY-AUDIT-AND-FIX-GUIDE.md`, `docs/CLIENT-40250-PORT.md`, + `docs/PARITY-GAP.md`: background only; trust the port-map, not their status text. - `oracle/run-diff-suite.sh`: Granny numerical comparison suite. -- `project/test_*_parity.gd` and `project/*_test.gd`: existing tests; inspect assertions before treating them as evidence. -## Typical verification commands - -Run a narrow Godot test with: +## Verification commands ```bash -godot --headless --path project --script project/test_name.gd +godot --headless --path project --script .gd # most project tests +cmake --build build-debug -j4 && ctest --test-dir build-debug --output-on-failure -j2 ``` -Some scripts expect the path relative to `project/` instead: - -```bash -godot --headless --path project --script test_name.gd -``` - -Follow the convention already used by the selected test. Always finish code changes with `git diff --check`. +If `build-debug/CMakeCache.txt` points at another checkout path, reconfigure first: +`cmake -S . -B build-debug -DCMAKE_BUILD_TYPE=Debug`. Always finish with `git diff --check`. diff --git a/.claude/skills/metin2-40250-parity-audit/SKILL.md b/.claude/skills/metin2-40250-parity-audit/SKILL.md index d6334e5b..357d3083 100644 --- a/.claude/skills/metin2-40250-parity-audit/SKILL.md +++ b/.claude/skills/metin2-40250-parity-audit/SKILL.md @@ -1,6 +1,6 @@ --- name: metin2-40250-parity-audit -description: Audit, implement, fix, or verify behavioral parity between the Metin2 40250 Windows C++ client and this Godot client. Use for 40250 comparison, 1:1 parity, missing original-client behavior, parity regressions, and continuation of the client audit. +description: Port, fix, or verify 1:1 parity between the Metin2 40250 Windows C++ client and this Godot client. Use for any 40250 comparison, 1:1 parity, missing original-client behavior, parity regression, or continuation of the client port/audit. Work is done by transliterating 40250 source units, not by hunting behavior differences. --- This is a compatibility entry point. Read `../../../.agents/skills/metin2-40250-parity-audit/SKILL.md` completely and follow it as the canonical skill. Resolve its relative references from the canonical skill directory.