Skip to content

packages client: define the distributable client artifact #303

Closed

Description

@Mathih13

This was generated by AI during triage.

Human Brief

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.
  • Packing does not modify the configured client.

Out of scope:

  • lyracore client sync
  • Executable modification

Activity

  1. added
    enhancementNew feature or request
    P3someday / nice-to-have
    ready-for-humanNeeds a maintainer: a decision, a maintainer's Realm, or coordination
    on Aug 24, 2026
  2. Mathih13 commented on Sep 1, 2026

    @Mathih13
    ContributorAuthor

    This was generated by AI during triage.

    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)
    • client sync, executable modification
  3. added
    ready-for-agentComplete enough to build from the issue alone, by a person or their agent
    and removed
    ready-for-humanNeeds a maintainer: a decision, a maintainer's Realm, or coordination
    on Sep 1, 2026
  4. Mathih13 commented on Sep 2, 2026

    @Mathih13
    ContributorAuthor

    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.

  5. Mathih13 commented on Sep 2, 2026

    @Mathih13
    ContributorAuthor

    Closing: every acceptance box is met at the code level, see the verification comment above.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    P3someday / nice-to-haveenhancementNew feature or requestready-for-agentComplete enough to build from the issue alone, by a person or their agent

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions