Skip to content

feat(config): ctld-tools inject — automatic .miz trigger injection (CTLD-TOOLS-MIZ-INJECT)#50

Merged
davidp57 merged 3 commits into
developfrom
feature/ctld-tools-miz-inject
Jul 20, 2026
Merged

feat(config): ctld-tools inject — automatic .miz trigger injection (CTLD-TOOLS-MIZ-INJECT)#50
davidp57 merged 3 commits into
developfrom
feature/ctld-tools-miz-inject

Conversation

@davidp57

@davidp57 davidp57 commented Jul 20, 2026

Copy link
Copy Markdown
Member

Delivers the roadmap item automatic .miz injection for ctld-tools.

What

  • ctld-tools inject --miz M.miz --userconfig CTLD_userConfig.lua [--out copy.miz] — inserts the
    generated Lua as an inline MISSION START trigger at rank 1 (runs before the CTLD trigger),
    idempotent (re-injection updates the same trigger, matched by a comment marker).
  • The mission trig/trigrules tables are patched in place: existing triggers are shifted and
    their in-code [idx] self-references rewritten — the approach VMCT's mission builder uses
    (which is why triggers-with-hardcoded-indices are not a blocker). Inline (a_do_script) per choice.
  • Vendored luadata (VMCT's index-preserving variant, keep_as_dict) under ctld_tools/vendor/,
    veaf_libs dependency stripped, excluded from ruff/mypy/coverage.

Validation

  • test_miz.py on the repo's martyr .miz: rank-1 trigger present + marked; existing triggers
    shifted with consistent [idx]; regenerated mission is valid Lua (executed via lupa);
    re-injection stays single. 29 tests green (ruff + mypy + pytest).
  • Final validation is a load in DCS — the round-trip is proven in Python, but only DCS confirms
    the mission loads and the trigger fires in order. The docs warn to back up + test in DCS.

Notes

  • I initially called this a wall (hardcoded trigger indices); VMCT already solves it by rewriting
    those indices on shift — recreated here.
  • Only remaining ctld-tools roadmap item: the interactive TUI.

Summary by Sourcery

Introduce automatic injection of generated CTLD user configuration Lua into DCS .miz missions via ctld-tools, and vendor Lua mission parsing utilities to support it.

New Features:

  • Add ctld-tools inject CLI command to insert a generated CTLD_userConfig.lua into a .miz as a first-rank MISSION START trigger, with optional output path and idempotent behavior.
  • Implement .miz mission reading, trigger rewriting, and user-config injection logic that shifts existing triggers and updates their indices while preserving mission validity.

Enhancements:

  • Vendor a specialized luadata library under ctld_tools/vendor for Lua mission table parse/serialize while excluding it from linting, typing, and coverage tooling.
  • Update ctld-tools documentation (EN/FR) and changelog to describe the new injection flow and advise backing up and validating missions in DCS.
  • Mark the corresponding roadmap item as delivered in the backlog and roadmap documents.

Build:

  • Adjust ruff, mypy, and coverage configuration to ignore the vendored Lua data library directory during quality checks.

Tests:

  • Add end-to-end tests around .miz injection to verify trigger placement, index shifting and rewriting, Lua validity of regenerated missions, and idempotent reinjection behavior.

…TLD-TOOLS-MIZ-INJECT)

`ctld-tools inject` inserts a generated CTLD_userConfig.lua into a .miz as a rank-1
MISSION START trigger (runs before the CTLD trigger), idempotently (re-injection
updates the same trigger, matched by comment). The mission trig/trigrules tables are
patched in place: existing triggers are shifted and their in-code [idx] self-references
rewritten (the VMCT mission-builder approach), recreated here.

Vendored luadata (index-preserving parse/serialize, keep_as_dict) under
ctld_tools/vendor/, excluded from lint/type/coverage. Round-trip tested: injected
mission reparses, is valid Lua (executed via lupa), and stays single after re-inject.
Final validation is a manual load in DCS. Docs (EN+FR) + inject command.
@sourcery-ai

sourcery-ai Bot commented Jul 20, 2026

Copy link
Copy Markdown

Reviewer's Guide

Adds a new ctld-tools inject CLI subcommand and supporting .miz manipulation utilities to automatically and idempotently inject a generated CTLD_userConfig.lua into a DCS mission as a rank-1 MISSION START trigger, plus vendorized Lua mission parsing, tests, and documentation/backlog updates.

Sequence diagram for ctld-tools inject CLI execution

sequenceDiagram
    actor MissionMaker
    participant TyperApp as Typer_app
    participant CLI as inject_cmd
    participant Miz as inject_userconfig
    participant Zip as zipfile_ZipFile
    participant LuaData as luadata

    MissionMaker->>TyperApp: ctld-tools inject --miz M.miz --userconfig CTLD_userConfig.lua --out out.miz
    TyperApp->>CLI: inject_cmd(miz, userconfig, out)
    CLI->>CLI: userconfig.read_text("utf-8")
    CLI->>Miz: inject_userconfig(miz, userconfig_lua, target)

    Miz->>Miz: read_mission(miz_path)
    Miz->>Zip: ZipFile.read("mission")
    Zip-->>Miz: mission_text
    Miz->>LuaData: unserialize(mission_text, keep_as_dict)
    LuaData-->>Miz: mission_table

    Miz->>Miz: inject_userconfig trigger rewrite

    Miz->>Miz: write_miz(mission, miz_path, out_path)
    Miz->>LuaData: serialize(mission)
    LuaData-->>Miz: mission_serialized
    Miz->>Zip: ZipFile(..., "w", ZIP_DEFLATED)
    Miz->>Zip: writestr("mission", mission_serialized)
    Zip-->>Miz: out.miz

    Miz-->>CLI: None
    CLI-->>MissionMaker: "inject: wrote out.miz"
Loading

File-Level Changes

Change Details Files
Introduce ctld-tools inject CLI command that writes a generated CTLD_userConfig.lua into a .miz mission as a first-run MISSION START trigger, optionally overwriting in-place or writing to a separate output file.
  • Add inject Typer subcommand accepting --miz, --userconfig, and optional --out parameters.
  • Wire the command to inject_userconfig to perform the mission mutation and emit a concise completion message.
tools/ctld-tools/ctld_tools/cli.py
Implement .miz mission parsing and trigger injection logic that patches trig/trigrules in place, shifting existing triggers, rewriting index self-references, and inserting an inline a_do_script trigger at rank 1 with an idempotent marker.
  • Add read_mission to unzip and parse the Lua mission file using luadata with keep_as_dict for trig and trigrules.
  • Add write_miz to rewrite the mission entry in a .miz safely via temp-file replacement, preserving other zip entries.
  • Provide helpers to pivot/unpivot trigger tables by trigger id, escape Lua strings, and regex-rewrite in-code [idx] references when renumbering triggers.
  • Implement inject_userconfig to remove any previously injected trigger by marker comment, renumber and rewrite existing triggers starting at id 2, create a new id-1 trigger (a_do_script, funcStartup, return(true), flag) plus matching trigrules entry with marker, and write the updated mission back to the .miz.
tools/ctld-tools/ctld_tools/miz.py
Vendor the luadata library and exclude it from linting, typing, and coverage tooling to provide stable Lua mission parse/serialize behavior.
  • Add ctld_tools/vendor/luadata package (I/O and serializer modules) and an empty vendor package initializer.
  • Update ruff configuration to exclude ctld_tools/vendor from lint checks.
  • Update mypy configuration to exclude ctld_tools/vendor from type-checking.
  • Update coverage configuration to omit vendor code from coverage metrics.
tools/ctld-tools/ctld_tools/vendor/__init__.py
tools/ctld-tools/ctld_tools/vendor/luadata/__init__.py
tools/ctld-tools/ctld_tools/pyproject.toml
.coveragerc?
tools/ctld-tools/pyproject.toml
Document the new automatic injection workflow and safety caveats in the mission-maker guides and changelog, and mark the roadmap item as delivered with an associated PRD.
  • Extend English and French ctld-tools mission-maker docs with the inject command in the CLI table, an "Automatic injection" section, usage example, and a warning to back up and validate missions in DCS.
  • Add an Unreleased changelog entry describing ctld-tools inject, the luadata vendoring, testing guarantees, and documentation updates.
  • Mark the CTLD-TOOLS-MIZ-INJECT roadmap item as delivered in dev/roadmap.md and add a backlog entry summarizing the lot.
  • Add a PRD under .backlog/CTLD-TOOLS-MIZ-INJECT/PRD.md capturing problem statement, solution, implementation details, and testing scope.
docs/mission-maker/ctld-tools.md
docs/mission-maker/ctld-tools.fr.md
CHANGELOG.md
dev/roadmap.md
.backlog/README.md
.backlog/CTLD-TOOLS-MIZ-INJECT/PRD.md
Add end-to-end tests that exercise .miz injection behavior, including trigger ordering, index shifting, Lua validity, and idempotent reinjection.
  • Introduce test_miz.py using the repo’s martyr mission to assert that an injected trigger appears at rank 1 with the expected comment and predicate and that existing triggers increase in count by one.
  • Verify that shifted func entries with conditions[...] self-references now point to their new key indices after renumbering.
  • Round-trip serialize the modified mission via luadata and execute it with lupa.LuaRuntime to ensure Lua syntax correctness.
  • Confirm idempotency by injecting twice and asserting only one marker trigger exists and that the final trigger body reflects the second injection content.
tools/ctld-tools/tests/test_miz.py

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've left some high level feedback:

  • The custom _escape_lua_string is quite minimal and could misbehave with more complex Lua payloads (e.g., embedded escape sequences or other control characters); consider centralizing Lua string escaping or leveraging luadata/lupa utilities to avoid subtle injection issues.
  • Both read_mission and inject_userconfig assume the presence and shape of mission['trig']/['trigrules'] without explicit validation; adding clear error messages or defensive checks when these structures are missing or malformed would make failures easier to diagnose for mission makers.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The custom `_escape_lua_string` is quite minimal and could misbehave with more complex Lua payloads (e.g., embedded escape sequences or other control characters); consider centralizing Lua string escaping or leveraging `luadata`/lupa utilities to avoid subtle injection issues.
- Both `read_mission` and `inject_userconfig` assume the presence and shape of `mission['trig']`/`['trigrules']` without explicit validation; adding clear error messages or defensive checks when these structures are missing or malformed would make failures easier to diagnose for mission makers.

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

@davidp57 davidp57 closed this Jul 20, 2026
@davidp57 davidp57 reopened this Jul 20, 2026

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've found 1 issue, and left some high level feedback:

  • The index-rewrite logic in _rewrite_indices uses a broad re.sub(rf"\[{old_id}\]", ...) which will replace any [old_id] substring in the compiled Lua; consider tightening the pattern (e.g. anchoring around known conditions[...]/actions[...] shapes or using more context) to avoid accidentally rewriting unrelated table index literals.
  • read_mission assumes the presence of a mission entry in the zip and UTF‑8 text without surfacing a clear error if either is missing/invalid; you might want to detect and raise a more explicit exception when the mission member is absent or decoding fails to make CLI failures easier to diagnose.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The index-rewrite logic in `_rewrite_indices` uses a broad `re.sub(rf"\[{old_id}\]", ...)` which will replace any `[old_id]` substring in the compiled Lua; consider tightening the pattern (e.g. anchoring around known `conditions[...]`/`actions[...]` shapes or using more context) to avoid accidentally rewriting unrelated table index literals.
- `read_mission` assumes the presence of a `mission` entry in the zip and UTF‑8 text without surfacing a clear error if either is missing/invalid; you might want to detect and raise a more explicit exception when the `mission` member is absent or decoding fails to make CLI failures easier to diagnose.

## Individual Comments

### Comment 1
<location path=".backlog/README.md" line_range="19" />
<code_context>
+| `CTLD-TOOLS-MIZ-INJECT` | ✅ merged (PR #50) | `ctld-tools inject`: insert the generated `CTLD_userConfig.lua` into a `.miz` as a rank-1 MISSION START trigger (idempotent), patching `trig`/`trigrules` with index-shift + in-code `[idx]` rewrite (VMCT approach). Vendored `luadata`. Round-trip tested (valid Lua, single after re-inject); final validation = DCS load. | `feature/ctld-tools-miz-inject` |
</code_context>
<issue_to_address>
**suggestion (typo):** Slightly awkward use of “re-inject” as a noun

The wording "single after re-inject" is grammatically awkward. Consider "single after re-injection" or "still single after re-injecting" for clearer prose.

```suggestion
| `CTLD-TOOLS-MIZ-INJECT` | ✅ merged (PR #50) | `ctld-tools inject`: insert the generated `CTLD_userConfig.lua` into a `.miz` as a rank-1 MISSION START trigger (idempotent), patching `trig`/`trigrules` with index-shift + in-code `[idx]` rewrite (VMCT approach). Vendored `luadata`. Round-trip tested (valid Lua, still single after re-injection); final validation = DCS load. | `feature/ctld-tools-miz-inject` |
```
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment thread .backlog/README.md
|-----|--------|-------------|--------|
| `FEAT-USERCONFIG-API` | ✅ merged (PR #45) | Replace broken Section 2 of `CTLD_userConfig.lua` with a safe MM API (`ctld.userSetup` callbacks + helpers), relocate `injectAACrates` to bootstrap, fix all parity bugs in userConfig template. | `feature/userconfig-api` |
| `CTLD-TOOLS-CONFIG` | ✅ merged (PR #46) | Lot 2 of `ctld-tools` ([ADR 0009](../dev/adr/0009-external-yaml-authoring-ctld-tools.md)): engine defaults moved out of `CTLD_config.lua` into `src/CTLD_config.yaml` (source of truth, sectioned mm-facing/advanced); isolated poetry package `tools/ctld-tools` (typer/ruamel/lupa, VMCT stack) with `extract` + `gen-config`; committed generated `CTLD_config_defaults.lua` + parity/drift guards + `python-quality` CI. `load()` copies `ctld.__configDefaults`. | `feature/ctld-tools-config` |
| `CTLD-TOOLS-MIZ-INJECT` | ✅ merged (PR #50) | `ctld-tools inject`: insert the generated `CTLD_userConfig.lua` into a `.miz` as a rank-1 MISSION START trigger (idempotent), patching `trig`/`trigrules` with index-shift + in-code `[idx]` rewrite (VMCT approach). Vendored `luadata`. Round-trip tested (valid Lua, single after re-inject); final validation = DCS load. | `feature/ctld-tools-miz-inject` |

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion (typo): Slightly awkward use of “re-inject” as a noun

The wording "single after re-inject" is grammatically awkward. Consider "single after re-injection" or "still single after re-injecting" for clearer prose.

Suggested change
| `CTLD-TOOLS-MIZ-INJECT` | ✅ merged (PR #50) | `ctld-tools inject`: insert the generated `CTLD_userConfig.lua` into a `.miz` as a rank-1 MISSION START trigger (idempotent), patching `trig`/`trigrules` with index-shift + in-code `[idx]` rewrite (VMCT approach). Vendored `luadata`. Round-trip tested (valid Lua, single after re-inject); final validation = DCS load. | `feature/ctld-tools-miz-inject` |
| `CTLD-TOOLS-MIZ-INJECT` | ✅ merged (PR #50) | `ctld-tools inject`: insert the generated `CTLD_userConfig.lua` into a `.miz` as a rank-1 MISSION START trigger (idempotent), patching `trig`/`trigrules` with index-shift + in-code `[idx]` rewrite (VMCT approach). Vendored `luadata`. Round-trip tested (valid Lua, still single after re-injection); final validation = DCS load. | `feature/ctld-tools-miz-inject` |

…-miz-inject

# Conflicts:
#	.backlog/README.md
#	CHANGELOG.md
@davidp57
davidp57 merged commit 0522ed4 into develop Jul 20, 2026
7 checks passed
@davidp57
davidp57 deleted the feature/ctld-tools-miz-inject branch July 20, 2026 20:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant