feat(config): ctld-tools inject — automatic .miz trigger injection (CTLD-TOOLS-MIZ-INJECT)#50
Conversation
…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.
Reviewer's GuideAdds a new ctld-tools Sequence diagram for ctld-tools inject CLI executionsequenceDiagram
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"
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
There was a problem hiding this comment.
Hey - I've left some high level feedback:
- The custom
_escape_lua_stringis 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 leveragingluadata/lupa utilities to avoid subtle injection issues. - Both
read_missionandinject_userconfigassume the presence and shape ofmission['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.Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
There was a problem hiding this comment.
Hey - I've found 1 issue, and left some high level feedback:
- The index-rewrite logic in
_rewrite_indicesuses a broadre.sub(rf"\[{old_id}\]", ...)which will replace any[old_id]substring in the compiled Lua; consider tightening the pattern (e.g. anchoring around knownconditions[...]/actions[...]shapes or using more context) to avoid accidentally rewriting unrelated table index literals. read_missionassumes the presence of amissionentry 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 themissionmember 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>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
| |-----|--------|-------------|--------| | ||
| | `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` | |
There was a problem hiding this comment.
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.
| | `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
Delivers the roadmap item automatic
.mizinjection forctld-tools.What
ctld-tools inject --miz M.miz --userconfig CTLD_userConfig.lua [--out copy.miz]— inserts thegenerated 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).
trig/trigrulestables are patched in place: existing triggers are shifted andtheir 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.luadata(VMCT's index-preserving variant,keep_as_dict) underctld_tools/vendor/,veaf_libsdependency stripped, excluded from ruff/mypy/coverage.Validation
test_miz.pyon the repo's martyr.miz: rank-1 trigger present + marked; existing triggersshifted with consistent
[idx]; regeneratedmissionis valid Lua (executed via lupa);re-injection stays single. 29 tests green (ruff + mypy + pytest).
the mission loads and the trigger fires in order. The docs warn to back up + test in DCS.
Notes
those indices on shift — recreated here.
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:
injectCLI command to insert a generatedCTLD_userConfig.luainto a .miz as a first-rank MISSION START trigger, with optional output path and idempotent behavior.Enhancements:
luadatalibrary under ctld_tools/vendor for Lua mission table parse/serialize while excluding it from linting, typing, and coverage tooling.Build:
Tests: