Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .backlog/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ authored **per lot, when the lot is started** (not in batch).

| Lot | Status | Description | Branch |
|-----|--------|-------------|--------|
| _(none)_ | | | |
| `REINTEGRATE-ORPHAN-TESTS` | ✅ pending merge | Rebuilt coverage for the 46 features tested only by dead FullGas relics — 6 busted tickets (158 tests, green in CI) + 1 live-DCS ticket (3 scenarios: BCN 30/30, RCN 10/10, VEH 22/22). Precedes & unblocks `CLEANUP-LEGACY-DCS-TESTS`. 10 relics were false orphans (already covered); 6 deferred to FullGas (`dev/fullgas-report.md`). PR #20. | feature/reintegrate-orphan-tests |

### Planned lots

Expand Down
72 changes: 72 additions & 0 deletions .backlog/REINTEGRATE-ORPHAN-TESTS/PRD.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
# Lot REINTEGRATE-ORPHAN-TESTS — rebuild coverage lost with the dead FullGas relics

Status: ✅ done — all 7 tickets complete (pending merge)
Branch: feature/reintegrate-orphan-tests → PR #20 → develop
Program: re-tooling CTLD on the VMCT model (see `.backlog/README.md`). Precedes and unblocks the
planned `CLEANUP-LEGACY-DCS-TESTS` purge.

## Problem Statement

`tests/dcs/noPlayer/` still holds ~194 dead FullGas relics (no `-- @tier:` header, `dofile` of
`C:/Users/Moi/.../DCS-CTLD_FG/recette/setup.lua`, absent `ctld_test` framework). The planned
`CLEANUP-LEGACY-DCS-TESTS` lot would purge them. But a coverage audit (cross-referencing the
tagged `@tier` scenarios and the busted `tests/ci/` suite by *tested symbol/assertion*, not by
file name) found that **62 features are covered ONLY by these relics** — and of those, **46 are
genuine gaps**: the behaviour is alive in `src/` but tested nowhere active. Purging without
re-integrating would silently lock in that coverage loss (it is already lost *de facto* — the
relics execute nothing — but the purge would make it permanent).

Crucially these are mostly *live-DCS-flavoured* behaviours (events, manager contracts, scene
structures, legacy wrappers) — not covered by the entity-level busted specs that exist today.

## Audit result (62 orphan features)

- **GAP (46)** — alive in `src/`, uncovered → re-integrate here.
- **COVERED (10)** — false orphans (covered under another name), relic is safe to purge, no test
action: F-024, F-026, F-042, F-072, F-073, F-074, F-076, F-081, F-082, F-111.
- **FULLGAS (6)** — deep refactor / human visual check, original-author intent required → hand to
FullGas (see `dev/fullgas-report.md`), NOT guessed here:
- F-010 `hideScan`→`stopScan` renamed, mark-removal contract to settle
- F-020 vehicle parachute refactored to `parachuteVehicle()` (already covered by `parachute_spec`)
- F-044 / F-090 `fobScene` redesigned 4→21 steps, structure assertions stale
- F-093 FOB unpack: `_onFOBBuilt` gone + beacon now offset −5 m from the centroid
- F-100 `spawnCrate`: two crates physically visible on the F10 map → human visual check (tier `ia`)

## Solution

**Busted-first.** Everything mockable against the DCS stubs → busted (`tests/ci/`, runs in CI,
fast, deterministic). Only behaviour that needs the real DCS engine (real object spawn, world
events, `dcs_native` unit handling) stays as a live-DCS tagged scenario.

Busted cannot be run locally (the Lua-for-Windows luarocks is too old to parse busted's modern
dependency constraints). We rely on CI as the runner (same posture as luacheck), with local
syntax validation via `luac5.1 -p`. The pilot ticket (01) is pushed first to validate the busted
pattern in CI before the remaining lots are written.

## Tickets (one per coherent test lot)

| # | Scope | Relics | Cible |
|---|-------|--------|-------|
| 01 | Crate lifecycle + events (PILOT) | F-027, F-028, F-029, F-030, F-031, F-032, F-041 | busted |
| 02 | Legacy API wrappers (routing + deprecation) | F-094, F-095, F-096, F-097, F-098 | busted |
| 03 | Scene structures + minefields | F-043, F-091, F-083, F-084, F-085, F-087 | busted |
| 04 | Deploy managers: AA assembly, FOB events, pack vehicle | F-021, F-022, F-023, F-012, F-013, F-099 | busted |
| 05 | Menu gating by config + player event wiring | F-048/049/050/052/053/054/055/056/075/077/088/089, F-025 | busted |
| 06 | JTAC config/deregister + recon auto-refresh | F-110, F-112, F-011 | busted |
| 07 | Live-DCS coverage (real engine) | F-006, F-007, F-092, F-009, F-018, F-019 | scénario `@tier` |

## User Stories

1. As a maintainer, I want the behaviours currently tested only by dead relics to have live,
running coverage, so that `CLEANUP-LEGACY-DCS-TESTS` can purge the relics without losing
anything.
2. As a developer, I want that coverage in busted/CI wherever possible, so it runs on every push
without a live DCS session.

## Non-goals

- Purging the relics themselves — that's `CLEANUP-LEGACY-DCS-TESTS`, after this lot.
- The 6 FULLGAS items — deferred to FullGas (documented in `dev/fullgas-report.md`).
- Re-testing the 10 COVERED features — already covered elsewhere.
- Raising the coverage ratchet as a goal in itself (it will rise as a side effect; the gate must
still pass).
40 changes: 40 additions & 0 deletions .backlog/REINTEGRATE-ORPHAN-TESTS/tickets/01-crate-lifecycle.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# 01 — Crate lifecycle manager methods + events (PILOT)

Status: ✅ done
Type: AFK

## What to build

`tests/ci/unit/crate_lifecycle_spec.lua` — busted coverage for the `CTLDCrateManager` *manager*
methods and their event contracts (the existing `crate_manager_spec.lua` covers only the
entity-level `crate:load/unload/unpack` transitions and `getCrateByName`/`getCratesInRange`).

Re-integrates relics:
- F-027 `registerMMCrate` — register mission-maker crate + guards (duplicate, unknown type)
- F-028 `loadCrate` — → LOADED, publishes `OnCrateLoaded`, guards (unknown, not-on-ground)
- F-029 `unloadCrate` — → LANDED, publishes `OnCrateUnloaded` (method) + `OnCrateSpawned`
- F-030 `unpackCrate` — → UNPACKED, publishes `OnCrateUnpacked`, unregisters
- F-031 `dropCrate` ≤ maxDropHeight — → LANDED, publishes `OnCrateUnloaded` (method="drop")
- F-032 `dropCrate` > maxDropHeight — destroyed, publishes `OnCrateDestroyed` (reason="drop_impact")
- F-041 `registerMMCrate` — publishes `OnMMCrateDetected`

## Pattern (pilot — validate in CI first)

- Capture events by subscribing to `EventDispatcher.getInstance()` around the call, then
`unsubscribe` (see `crate_manager_spec.lua` `spawnCrate` block for the proven approach).
- `unloadCrate`/`dropCrate`(safe) re-spawn a DCS static → mock `coalition.addStaticObject` +
`StaticObject.getByName` in `before_each`/`after_each` (same as the `spawnCrate` describe block).
- Reset `cm.crates = {}` in `before_each`.

## Acceptance criteria

- [ ] `luac5.1 -p` clean.
- [ ] Covers F-027/028/030/041 (pilot subset — no static respawn) AND F-029/031/032 (with the
addStaticObject mock).
- [ ] Each manager method asserted on: state transition + event payload (count + key fields) +
at least one guard (no-op / no event on invalid input).
- [ ] `busted` job green in CI.

## Blocked by

None. First ticket — its green CI run validates the busted pattern for tickets 02–06.
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# 02 — Legacy API wrappers: routing + deprecation

Status: ✅ done
Type: AFK

## What to build

Busted coverage for the `src/legacy/legacy_api.lua` wrappers — each must route to its modern
target and emit a deprecation warning. Pure logic, fully mockable.

Re-integrates relics:
- F-094 Troops wrappers (6 fn) — routing + deprecation warning
- F-095 Zones wrappers (10 fn) — routing (e.g. `activatePickupZone`→`setTroopZoneActive`)
- F-096 Crates wrappers (3 fn) + `spawnCrateAtZone` functional
- F-097 `createRadioBeaconAtZone` → `createAtZone` + deprecation warning
- F-098 JTAC wrappers (3 fn) — routing (e.g. `JTACAutoLase`→`autoLase`)

## Approach

For each wrapper: stub the modern target method (spy), call the legacy fn, assert the target was
called with the right args and that a deprecation warning was logged. Confirm signatures against
`src/legacy/legacy_api.lua` (relics point at the old `src/compat/` path — dead).

## Acceptance criteria

- [ ] `luac5.1 -p` clean.
- [ ] Every wrapper listed above asserted: routes to correct target + args preserved.
- [ ] Deprecation warning path exercised at least once per wrapper family.
- [ ] `busted` job green.

## Blocked by

Ticket 01 (pattern validation).
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# 03 — Scene structures + minefields

Status: ✅ done
Type: AFK

## What to build

Busted coverage for scene model structure and minefield mine-count logic (pure/deterministic).

Re-integrates relics:
- F-043 "FARP Alpha" scene — structure (steps, registry keys, polar layout) via the registered
scene model (`src/scenes/CTLD_farpAlphaScene.lua`)
- F-091 `farpScene` — structure (6 steps, SINGLE_HELIPAD/FARP_Tent…), Part 1 only (visual spawn
is the `ia` part, out of scope here)
- F-083 `setLandMine` 1×1 → 1 mine
- F-084 `setLandMine` 5×15 staggered → 68 mines (8×5 + 7×4)
- F-085 `setLandMine` 4×3 staggered → 11 mines (4 + 3 + 4)
- F-087 `setLandMineAuto` parametric count + single-mine branch + guards

## Approach

Structure: assert the registered scene model's step count / keys / polar params against
`src/scenes/*`. Minefields: stub the spawn primitive and count invocations for each grid.

## Acceptance criteria

- [ ] `luac5.1 -p` clean.
- [ ] Scene structure assertions track the CURRENT models (not the stale relic figures — verify
against `src/scenes/` before writing expected values).
- [ ] Mine counts asserted for 1×1, 5×15, 4×3, and the auto/parametric path.
- [ ] `busted` job green.

## Blocked by

Ticket 01.
36 changes: 36 additions & 0 deletions .backlog/REINTEGRATE-ORPHAN-TESTS/tickets/04-deploy-managers.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# 04 — Deploy managers: AA assembly, FOB events, pack vehicle

Status: ✅ done
Type: AFK

## What to build

Busted coverage for the crate-assembly, FOB-manager and pack-vehicle contracts.

Re-integrates relics:
- F-021 AA assembly complete (`tryUnpackOrRepair`/`_assemble`) → `OnAASystemDeployed` + crates destroyed
- F-022 AA assembly incomplete → no deployment
- F-023 AA repair (`_repair`) → `OnAASystemRepaired` + group replaced
- F-012 FOB deployed (`_registerDeployedFOB`) → `OnFOBDeployed` payload + `_objectToFOB` reverse lookup
- F-013 FOB `onDead`/`_destroyFOB` → integrity threshold + `OnFOBDestroyed` + cleanup
- F-099 `findPackableVehicles` + `packVehicle` → `OnVehiclePacked` + crates spawned

## Approach

Event capture via `EventDispatcher`. For AA/FOB/pack: stub spawn/destroy primitives
(`coalition.addStaticObject`, group spawn, `crate:destroy`) and assert events + registry effects.
NB (from audit): `OnAASystemRepaired` is published nowhere else — F-023 is its only coverage.
Pack vehicle now spawns crates via `spawnCratesAligned` and refreshes via deferred
`timer.scheduleFunction` — assert accordingly, not the stale relic assumptions.

## Acceptance criteria

- [ ] `luac5.1 -p` clean.
- [ ] AA: complete (deploy + crates consumed), incomplete (no deploy), repair (event) all asserted.
- [ ] FOB: deploy event + reverse lookup, destroy event + cleanup asserted.
- [ ] Pack vehicle: `findPackableVehicles` result + `packVehicle` event/crates asserted.
- [ ] `busted` job green.

## Blocked by

Ticket 01.
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# 05 — Menu gating by config + player event wiring

Status: ✅ done
Type: AFK

## What to build

Busted coverage for F10 menu section gating (by config flag / transport capability) and the
player-manager event wiring.

Re-integrates relics:
- F-048 buildMenu all flags ON → all sections present
- F-049 `enableCrates`=false → Request Equipment/Crate Commands absent, Smoke/Beacons present
- F-050 `enabledRadioBeaconDrop`=false → Radio Beacons absent
- F-052 `JTAC_jtacStatusF10`=false → JTAC absent
- F-053 `enabledFOBBuilding`=false → List FOBs absent (under Crate)
- F-054 `enablePackingVehicles`=false → Pack Vehicle absent
- F-055 non-transport player → root + Check Cargo only; RECON/JTAC still present
- F-056 `canCarryVehicles`=true → Vehicle Commands present
- F-075 clearBranch + repopulate + refresh → new cmds present, old absent
- F-077 `refreshMenuForGroup` unknown group → `{success=false, refreshedCount=0}`
- F-088 `_loadUserConfig` ingests `ctld_config_user.customLoadableGroups`/`disableLoadableGroups`
- F-089 troop menu filters by disabled / side / capacity
- F-025 `OnVehicleLoaded/Unloaded` events → `player.loadedVehicles` updated

## Approach

Use the `pm:buildMenu(playerObj)` + `menu:_getNode(path)` pattern (confirmed working in
`troop_multi_spec`). Toggle `ctld.gs(configKey)` per test (save/restore). Section presence via
node lookup. NB: `refresh()` is debounced/async now — drive synchronous rebuilds via
`refreshMenuForGroup`. F-089: `buildMenu(unit,gid,opts)` is gone → target `refreshMenuSection`
(side filter at `CTLD_troop.lua:1858`).

## Acceptance criteria

- [ ] `luac5.1 -p` clean.
- [ ] Each config flag toggles the expected section on/off; non-transport & capacity gates asserted.
- [ ] `refreshMenuForGroup` unknown-group failure shape asserted.
- [ ] `_loadUserConfig` custom+disable ingestion asserted.
- [ ] Player `loadedVehicles` event wiring asserted.
- [ ] `busted` job green.

## Blocked by

Ticket 01.
31 changes: 31 additions & 0 deletions .backlog/REINTEGRATE-ORPHAN-TESTS/tickets/06-jtac-recon.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# 06 — JTAC config/deregister + recon auto-refresh

Status: ✅ done
Type: AFK

## What to build

Busted coverage for JTAC config defaults / deregistration and recon auto-refresh.

Re-integrates relics:
- F-110 `JTAC_unitTypeNames` config defaults (Hummer / SKP-11 per coalition, drone radius/altitude)
- F-112 `deregisterJTAC` — silent: no false `OnJTACDead`, laser code returned to pool, idempotent
- F-011 recon `enableAutoRefresh` / `disableAutoRefresh` + events (previous/new state)

## Approach

F-110: pure config assertions (`ctld.gs("JTAC_unitTypeNames")` etc.). F-112: sandbox — register a
JTAC, deregister, assert no `OnJTACDead` fired, `_laserPool` code freed, second deregister is a
no-op. F-011: subscribe to the auto-refresh events, toggle, assert payload state fields.

## Acceptance criteria

- [ ] `luac5.1 -p` clean.
- [ ] JTAC config defaults asserted per coalition.
- [ ] `deregisterJTAC`: no `OnJTACDead`, code pool freed, idempotent — all asserted.
- [ ] Recon auto-refresh enable/disable events asserted.
- [ ] `busted` job green.

## Blocked by

Ticket 01.
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# 07 — Live-DCS coverage (real engine required)

Status: ✅ done
Type: hybrid (AFK authoring + live DCS validation)

## What to build

Tagged `@tier` scenarios under `tests/dcs/noPlayer/` (contract-of-return, injected via
VEAF-dcs-bridge) for the behaviours that genuinely need the real DCS engine — not busted-able.

Re-integrates relics:
- F-006 `dropBeacon` — spawns 3 real units + freq + `OnBeaconDropped` (real spawn)
- F-007 `removeClosestBeacon` — removal + `OnBeaconRemoved` (reason=manual)
- F-092 `dropBeacon` with `overridePosition`=centroid, isFOB → infinite battery
- F-009 recon `scan()` — `OnReconScan` payload (activeLayers/targets), needs real enemies in mission
- F-018 `loadVehicle` method=`dcs_native` → LOADED + `OnVehicleLoaded` (real DCS unit)
- F-019 `unloadVehicle` method=`dcs_native` on ground → WAITING + `OnVehicleUnloaded`

## Approach

New scenarios from `tests/dcs/_template_noPlayer.lua` (or `_template_scenario.lua`), tier `auto`
or `auto-check`. Follow the return contract (`_SCN_<ID>_RESULT`, verdict grammar). Validate live
via `python tools/integration-runner/run_scenarios.py --scenario <name> --no-ai` against a running
DCS mission (requires David's DCS + dcs-serve up).

NB: this is the ONLY ticket needing a live DCS session; it runs after the busted tickets.
Corrections to relic assumptions flagged by the audit (F-018 `unit` kept alive in dcs_native;
F-092 beacon position) must be applied when authoring.

## Acceptance criteria

- [ ] Each scenario carries a valid `-- @tier:` header and the return contract.
- [ ] `luac5.1 -p` clean on each.
- [ ] Each scenario PASSes live via the headless runner (needs DCS up — validate with David).

## Blocked by

Tickets 01–06 (busted lots first). Live validation gated on a DCS session.
3 changes: 3 additions & 0 deletions tests/ci/helpers/loader.lua
Original file line number Diff line number Diff line change
Expand Up @@ -52,3 +52,6 @@ dofile(SRC .. "CTLD_player.lua")

-- ── Orchestrator ──────────────────────────────────────────────
dofile(SRC .. "CTLD_core.lua")

-- ── Legacy v1→v2 API wrappers (last in listToMerge, before CTLD_userConfig) ──
dofile(SRC .. "legacy/legacy_api.lua")
Loading