You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
packages client: define the distributable client artifact #303
Category: enhancement Summary: Set the legal and file-layout contract for client pack --out before implementing distribution.
Why this needs a human:
The command creates an artifact intended for players. A maintainer must decide what may be redistributed and obtain any legal review needed for Blizzard-derived or locally generated files.
Current behavior:
The existing packer writes a patch into the Operator's configured client and installs addons. It does not define a standalone distributable layout.
Desired behavior:
Decide whether the output contains an MPQ, addons, an archive around both, or another explicit layout. Define overwrite behavior, stale output cleanup, provenance, and which inputs may enter the artifact. Only then add lyracore client pack --out <directory> without touching the configured client.
Acceptance criteria:
The approved artifact layout and redistribution boundary are documented.
The command refuses unapproved Blizzard-derived inputs.
Existing output handling is explicit and cannot mix stale files into a new artifact.
The artifact records the enabled Package set and source revisions.
Both decisions are settled (maintainer, 2026-09-01): the artifact is a directory tree with an optional zip, and the licensing firewall holds — no baseline-derived file enters it.
Agent Brief
Category: enhancement Summary: Add lyracore client pack --out <directory>: a distributable, provenance-stamped artifact of package-authored client content only.
Current behavior:
The packer writes a patch into the Operator's configured client and installs addons. There is no standalone distributable layout.
Desired behavior:
client pack --out <dir> writes a directory mirroring a client install: the patch MPQ holding package-authored content only, Interface/AddOns/ with the enabled Packages' addons, and a provenance manifest recording the enabled Package set and each source revision. An optional flag zips that tree.
The firewall is enforced by provenance, not filename: any input derived from the operator's client baseline (extracted stock files, transformed FrameXML/GlueXML) is refused with the input and its origin named. Only package-authored files enter.
Output handling is explicit: packing into a directory it did not previously write (per its own manifest) refuses rather than mixing; repacking replaces the prior artifact wholly, so stale files from a removed Package cannot survive.
Packing never reads from or writes to the configured client beyond reading package sources; client sync is untouched.
The work lands in the sibling lyracore-cli repo; the .lyracore-cli-rev pin bump defers to the chain-head integration PR per convention.
Acceptance criteria:
The artifact contains the MPQ, AddOns tree, and manifest; a zip is produced only on request.
A baseline-derived input fails the pack, naming the file and why.
Repacking after disabling a Package leaves no trace of it in the artifact.
Packing into a foreign non-empty directory refuses.
The manifest names every included Package and its exact source revision.
The configured client is byte-identical before and after packing.
Out of scope:
A player-side tool for applying UI transforms locally (future work; consequence of the firewall)
Verified against CLI commit 72ed618 (feat(client): add client pack --out DIR [--zip], read at the pin e55a87dc54617821552992c683d3c91af7217060) and core PR #392 (feat(packages): client pack artifact and UI Transforms, merged at f186f1b, importer/src/pack_client.rs).
The artifact contains the MPQ, AddOns tree, and manifest; a zip is produced only on request. client pack --out drives lyracore-importer --pack-out, writing Data/patch-3.MPQ (only when a source ships an mpq/ file), Interface/AddOns/<Name>/, and lyracore-client-pack.json. --zip is a separate opt-in step. Proven by CLI tests zip_renders_exactly_one_call_after_the_manifest_exists and without_zip_there_is_no_zip_call.
A baseline-derived input fails the pack, naming the file and why. importer/src/pack_client.rs's Origin enum and refuse_baseline_derived refuse any Origin::BaselineDerived file before writing anything, naming the file and its baseline source. Proven by pack_out_refuses_a_baseline_derived_file_before_writing_anything.
Repacking after disabling a Package leaves no trace of it in the artifact. CLI's prepare_out wholly clears a directory it owns (by manifest) before every repack, and package_entries filters to PackageState::Enabled only, so a disabled Package's manifest entry and files both disappear on the next pack. Proven by a_directory_with_a_prior_manifest_is_emptied_then_packed.
Packing into a foreign non-empty directory refuses. Proven by a_non_empty_directory_without_a_manifest_is_refused_and_no_runner_call_happens (CLI) and the importer's own directory-ownership checks (the_client_pack_output_dir_is_an_input_on_its_own).
The manifest names every included Package and its exact source revision. package_entries reads source_kind/source/revision fresh from each enabled Package's stamp. Proven by the_manifest_lists_every_enabled_package_with_a_fresh_identity_and_the_files_in_out.
The configured client is byte-identical before and after packing. pack never runs --apply or --pack-client, only --pack-out against a separate --out directory, and refuses an --out inside the configured client-data path outright. Proven by the_importer_is_built_before_it_packs_with_pack_out_never_apply_or_pack_client and out_inside_the_configured_client_data_path_is_refused_and_nothing_runs; the importer's own guard is proven by the_two_client_packers_refuse_to_run_together and the_client_pack_output_dir_refuses_apply.
Also confirmed, as this ticket asked beyond the checklist:
docs/development-cli.md documents client pack --out/--zip, the artifact layout, and the licensing firewall (lines ~611-636).
The importer's Origin seam (importer/src/pack_client.rs) refuses baseline-derived input by provenance, not filename — both a DBC overlay and a UI Transform output are tagged Origin::BaselineDerived and refused the same way.
Ran cargo test --lib cmd::client in a detached CLI worktree at the pin commit: 21 passed. Ran cargo test -p lyracore-importer in the core checkout: 332 passed, 2 ignored (live-client targets, out of scope here). cargo clippy --all-targets and cargo +1.85 check are clean on the CLI side.
Every box is met at the code level. Closing.
Verified by Claude (model claude-sonnet-5) via Claude Code subagent.
Activity
Mathih13 commentedon Sep 1, 2026
Both decisions are settled (maintainer, 2026-09-01): the artifact is a directory tree with an optional zip, and the licensing firewall holds — no baseline-derived file enters it.
Agent Brief
Category: enhancement
Summary: Add
lyracore client pack --out <directory>: a distributable, provenance-stamped artifact of package-authored client content only.Current behavior:
The packer writes a patch into the Operator's configured client and installs addons. There is no standalone distributable layout.
Desired behavior:
client pack --out <dir>writes a directory mirroring a client install: the patch MPQ holding package-authored content only,Interface/AddOns/with the enabled Packages' addons, and a provenance manifest recording the enabled Package set and each source revision. An optional flag zips that tree.client syncis untouched..lyracore-cli-revpin bump defers to the chain-head integration PR per convention.Acceptance criteria:
Out of scope:
client sync, executable modificationMathih13 commentedon Sep 2, 2026
Verified against CLI commit 72ed618 (
feat(client): add client pack --out DIR [--zip], read at the pine55a87dc54617821552992c683d3c91af7217060) and core PR #392 (feat(packages): client pack artifact and UI Transforms, merged at f186f1b, importer/src/pack_client.rs).client pack --outdriveslyracore-importer --pack-out, writingData/patch-3.MPQ(only when a source ships anmpq/file),Interface/AddOns/<Name>/, andlyracore-client-pack.json.--zipis a separate opt-in step. Proven by CLI testszip_renders_exactly_one_call_after_the_manifest_existsandwithout_zip_there_is_no_zip_call.importer/src/pack_client.rs'sOriginenum andrefuse_baseline_derivedrefuse anyOrigin::BaselineDerivedfile before writing anything, naming the file and its baseline source. Proven bypack_out_refuses_a_baseline_derived_file_before_writing_anything.prepare_outwholly clears a directory it owns (by manifest) before every repack, andpackage_entriesfilters toPackageState::Enabledonly, so a disabled Package's manifest entry and files both disappear on the next pack. Proven bya_directory_with_a_prior_manifest_is_emptied_then_packed.a_non_empty_directory_without_a_manifest_is_refused_and_no_runner_call_happens(CLI) and the importer's own directory-ownership checks (the_client_pack_output_dir_is_an_input_on_its_own).package_entriesreadssource_kind/source/revisionfresh from each enabled Package's stamp. Proven bythe_manifest_lists_every_enabled_package_with_a_fresh_identity_and_the_files_in_out.packnever runs--applyor--pack-client, only--pack-outagainst a separate--outdirectory, and refuses an--outinside the configured client-data path outright. Proven bythe_importer_is_built_before_it_packs_with_pack_out_never_apply_or_pack_clientandout_inside_the_configured_client_data_path_is_refused_and_nothing_runs; the importer's own guard is proven bythe_two_client_packers_refuse_to_run_togetherandthe_client_pack_output_dir_refuses_apply.Also confirmed, as this ticket asked beyond the checklist:
docs/development-cli.mddocumentsclient pack --out/--zip, the artifact layout, and the licensing firewall (lines ~611-636).importer/src/pack_client.rs) refuses baseline-derived input by provenance, not filename — both a DBC overlay and a UI Transform output are taggedOrigin::BaselineDerivedand refused the same way.Ran
cargo test --lib cmd::clientin a detached CLI worktree at the pin commit: 21 passed. Rancargo test -p lyracore-importerin the core checkout: 332 passed, 2 ignored (live-client targets, out of scope here).cargo clippy --all-targetsandcargo +1.85 checkare clean on the CLI side.Every box is met at the code level. Closing.
Verified by Claude (model claude-sonnet-5) via Claude Code subagent.
Mathih13 commentedon Sep 2, 2026
Closing: every acceptance box is met at the code level, see the verification comment above.