Limit-order lifecycle parser trusts forgeable contract_address attribute (forged fills/cancels for any pair) #285

Closed
opened 2026-06-03 07:19:51 +00:00 by Brouie · 45 comments
Brouie commented 2026-06-03 07:19:51 +00:00 (Migrated from gitlab.com)

Severity: High
Reachability: Permissionless. Any deployed contract can emit the right attributes in its own tx.
Affected: limit-order lifecycle parsing (indexer/src/indexer/parser.rs).
Root cause: the parser treats the non-reserved contract_address attribute as authoritative for "which pair emitted this", but any contract can set that attribute to any value.

Summary

The parser recovers the emitting contract for a limit_order_fill / cancel / placement by scanning backward to the nearest contract-address attribute, and it accepts two keys as that source: _contract_address and contract_address (is_wasm_contract_addr_key). The underscore form is runtime-reserved — wasmd stamps it and contracts can't set _-prefixed keys. But contract_address (no underscore) is an ordinary custom attribute any contract can emit with any value.

So a malicious contract emits, in its own event stream:

contract_address = <victim_pair_address>
action          = limit_order_fill
... forged fill fields ...

wasm_contract_addr_before finds the forged contract_address (it's nearer than the runtime's real _contract_address), so the parser attributes the forged fill to the victim pair. process_limit_order_fill then looks the pair up by that address and inserts the fill under the real pair id — there's no check that the recovered address matches the reserved _contract_address the runtime actually stamped.

Same trick forges cancellations (mark a victim's live order cancelled, hiding it from the API/frontend) and placements. It doesn't touch on-chain state, but it corrupts the fills, order lifecycle, and trader analytics the indexer serves — for any pair, from anyone.

Current codebase

  • parser.rs is_wasm_contract_addr_key: key == "_contract_address" || key == "contract_address".
  • wasm_contract_addr_before: backward scan to the nearest such key — forged value wins over the reserved one.
  • process_limit_order_fill / cancel / placement handlers: trust fill.pair_address (the recovered value); no cross-check against the runtime-reserved _contract_address.
  1. Only trust the runtime-reserved _contract_address for contract scoping. Drop contract_address (no underscore), or treat it as data, never as the emitter.
  2. Belt and suspenders: when scoping an event, require the recovered address to equal the reserved _contract_address for that logical emission; reject mismatches.
  3. Persist lifecycle rows only for addresses that resolve to a factory-created pair (verify provenance in discovery, not just "is it a contract").

Acceptance criteria

  • A contract emitting contract_address = <victim_pair> + action = limit_order_fill does NOT produce a fill row attributed to the victim pair.
  • Forged cancel / placement events can't alter a victim pair's served lifecycle.
  • Only the runtime-stamped emitter scopes a lifecycle event.

Test plan (attack / abuse)

case expect
malicious contract forges fill for known victim pair dropped, no row
malicious contract forges cancel for a victim's live order victim order still shown active
genuine pair fill parsed and attributed correctly (no regression)
**Severity:** High **Reachability:** Permissionless. Any deployed contract can emit the right attributes in its own tx. **Affected:** limit-order lifecycle parsing (`indexer/src/indexer/parser.rs`). **Root cause:** the parser treats the non-reserved `contract_address` attribute as authoritative for "which pair emitted this", but any contract can set that attribute to any value. ## Summary The parser recovers the emitting contract for a `limit_order_fill` / cancel / placement by scanning backward to the nearest contract-address attribute, and it accepts **two** keys as that source: `_contract_address` and `contract_address` (`is_wasm_contract_addr_key`). The underscore form is runtime-reserved — wasmd stamps it and contracts can't set `_`-prefixed keys. But `contract_address` (no underscore) is an ordinary custom attribute any contract can emit with any value. So a malicious contract emits, in its own event stream: ``` contract_address = <victim_pair_address> action = limit_order_fill ... forged fill fields ... ``` `wasm_contract_addr_before` finds the forged `contract_address` (it's nearer than the runtime's real `_contract_address`), so the parser attributes the forged fill to the victim pair. `process_limit_order_fill` then looks the pair up by that address and inserts the fill under the real pair id — there's no check that the recovered address matches the reserved `_contract_address` the runtime actually stamped. Same trick forges cancellations (mark a victim's live order cancelled, hiding it from the API/frontend) and placements. It doesn't touch on-chain state, but it corrupts the fills, order lifecycle, and trader analytics the indexer serves — for any pair, from anyone. ## Current codebase - `parser.rs` `is_wasm_contract_addr_key`: `key == "_contract_address" || key == "contract_address"`. - `wasm_contract_addr_before`: backward scan to the nearest such key — forged value wins over the reserved one. - `process_limit_order_fill` / cancel / placement handlers: trust `fill.pair_address` (the recovered value); no cross-check against the runtime-reserved `_contract_address`. ## Recommended direction 1. Only trust the runtime-reserved `_contract_address` for contract scoping. Drop `contract_address` (no underscore), or treat it as data, never as the emitter. 2. Belt and suspenders: when scoping an event, require the recovered address to equal the reserved `_contract_address` for that logical emission; reject mismatches. 3. Persist lifecycle rows only for addresses that resolve to a factory-created pair (verify provenance in discovery, not just "is it a contract"). ## Acceptance criteria - [ ] A contract emitting `contract_address = <victim_pair>` + `action = limit_order_fill` does NOT produce a fill row attributed to the victim pair. - [ ] Forged cancel / placement events can't alter a victim pair's served lifecycle. - [ ] Only the runtime-stamped emitter scopes a lifecycle event. ## Test plan (attack / abuse) | case | expect | |---|---| | malicious contract forges fill for known victim pair | dropped, no row | | malicious contract forges cancel for a victim's live order | victim order still shown active | | genuine pair fill | parsed and attributed correctly (no regression) |
PlasticDigits commented 2026-06-03 10:52:26 +00:00 (Migrated from gitlab.com)

All 3 approved.
Additionally need demonstration of the attack in the codebase, and tests to prevent regression.

All 3 approved. Additionally need demonstration of the attack in the codebase, and tests to prevent regression.
Brouie commented 2026-06-04 05:27:01 +00:00 (Migrated from gitlab.com)

Fixed directions 1+2 + the attack demo + regression tests you asked for. Direction 3 (factory provenance) flagged as a follow-up — details below.

Fix (directions 1+2): dropped the no-underscore contract_address from emitter scoping in parser.rs (wasm_contract_addr + is_wasm_contract_addr_key) — only the wasmd-stamped _contract_address scopes a lifecycle event now; the no-underscore form is data, never the emitter. Since the recovered address is always the reserved one, that satisfies both "only trust _contract_address" and "recovered == reserved" in one change.

Attack demonstrated in-codebase (and proven non-vacuous): added forged_contract_address_fill_not_attributed_to_victim_pair and ..._cancel_... — a malicious emitter stamps real _contract_address=terra1attacker, then forges contract_address=terra1victimpair before action, and the test asserts the row scopes to the attacker, NOT the victim. I reverted the predicate to the vulnerable form and confirmed both tests FAIL (the forged value attributes to terra1victimpair) — i.e. the attack reproduces — then restored the fix and they pass. Plus genuine_fill_with_both_contract_address_keys_attributes_to_pair (no regression on the real dual-key shape).

No regression — verified against the real chain: a live v4 limit_order_fill tx carries _contract_address=<pair> (runtime, before action) AND the pair's own contract_address=<pair> convenience attr (after action, same value), so legit events scope correctly. Pre-existing test fixtures that used the no-underscore key as the SOLE scope (modeled a shape the chain never emits) were corrected to _contract_address. Full parser suite 29/29.

Direction 3 (factory provenance) — follow-up, flagged: with 1+2 in, a forged event now scopes to the attacker's OWN _contract_address. process_limit_order_fill then resolves that address and, if unknown, calls discover_new_pair, which adopts ANY contract answering {"pair":{}} (pair_discovery.rs). So an attacker whose contract answers {"pair":{}} self-corrupts their own adopted fake pair — NOT a victim, much lower severity. Closing that means discover_new_pair must verify the address is in the factory's authoritative pair list, which is the pair-discovery trust work that clusters with #279/#286/#287 (store pairs in Postgres via factory). Recommend tracking it there rather than bolting a factory query into the lifecycle path here.

Branch qa/285-forged-contract-address-parser, MR fork→main (no closing keyword). All AC items about victim-targeting are met; #3 residual is attacker-self-corruption pending the provenance follow-up. @PlasticDigits

Fixed directions 1+2 + the attack demo + regression tests you asked for. Direction 3 (factory provenance) flagged as a follow-up — details below. **Fix (directions 1+2)**: dropped the no-underscore `contract_address` from emitter scoping in `parser.rs` (`wasm_contract_addr` + `is_wasm_contract_addr_key`) — only the wasmd-stamped `_contract_address` scopes a lifecycle event now; the no-underscore form is data, never the emitter. Since the recovered address is always the reserved one, that satisfies both "only trust `_contract_address`" and "recovered == reserved" in one change. **Attack demonstrated in-codebase (and proven non-vacuous)**: added `forged_contract_address_fill_not_attributed_to_victim_pair` and `..._cancel_...` — a malicious emitter stamps real `_contract_address=terra1attacker`, then forges `contract_address=terra1victimpair` before `action`, and the test asserts the row scopes to the attacker, NOT the victim. I reverted the predicate to the vulnerable form and confirmed **both tests FAIL** (the forged value attributes to terra1victimpair) — i.e. the attack reproduces — then restored the fix and they pass. Plus `genuine_fill_with_both_contract_address_keys_attributes_to_pair` (no regression on the real dual-key shape). **No regression — verified against the real chain**: a live v4 `limit_order_fill` tx carries `_contract_address=<pair>` (runtime, before action) AND the pair's own `contract_address=<pair>` convenience attr (after action, same value), so legit events scope correctly. Pre-existing test fixtures that used the no-underscore key as the SOLE scope (modeled a shape the chain never emits) were corrected to `_contract_address`. Full parser suite 29/29. **Direction 3 (factory provenance) — follow-up, flagged**: with 1+2 in, a forged event now scopes to the attacker's OWN `_contract_address`. `process_limit_order_fill` then resolves that address and, if unknown, calls `discover_new_pair`, which adopts ANY contract answering `{"pair":{}}` (pair_discovery.rs). So an attacker whose contract answers `{"pair":{}}` self-corrupts their own adopted fake pair — NOT a victim, much lower severity. Closing that means `discover_new_pair` must verify the address is in the factory's authoritative pair list, which is the pair-discovery trust work that clusters with #279/#286/#287 (store pairs in Postgres via factory). Recommend tracking it there rather than bolting a factory query into the lifecycle path here. Branch `qa/285-forged-contract-address-parser`, MR fork→main (no closing keyword). All AC items about victim-targeting are met; #3 residual is attacker-self-corruption pending the provenance follow-up. @PlasticDigits
Brouie commented 2026-06-04 05:27:04 +00:00 (Migrated from gitlab.com)

mentioned in merge request !744

mentioned in merge request !744
Brouie commented 2026-06-04 06:30:06 +00:00 (Migrated from gitlab.com)

mentioned in issue #287

mentioned in issue #287
PlasticDigits commented 2026-06-04 08:04:40 +00:00 (Migrated from gitlab.com)

mentioned in commit 31d090c12a

mentioned in commit 31d090c12a2c5143a2a7853ec45646326bd77d58
Brouie commented 2026-06-05 01:19:18 +00:00 (Migrated from gitlab.com)

mentioned in merge request !750

mentioned in merge request !750
Brouie commented 2026-06-05 01:21:12 +00:00 (Migrated from gitlab.com)

Verified the forgery vector is closed at the parser, with the attack demo + regression tests you asked for. Mapping the AC:

AC1 (forged contract_address = victim_pair + action = limit_order_fill doesn't attribute a fill to the victim): met. is_wasm_contract_addr_key / wasm_contract_addr now match only the runtime-reserved _contract_address; the no-underscore form is data, never the emitter. The forged fill re-scopes to the attacker's own _contract_address, not the victim. Test forged_contract_address_fill_not_attributed_to_victim_pair passes and is non-vacuous (reverting the predicate makes it fail).

AC2 (forged cancel/placement can't alter a victim's served lifecycle): met. Cancel was already covered (forged_contract_address_cancel_not_attributed_to_victim_pair). Placement was closed at source (same reserved-only predicate on the placement parse paths) but had no named test — added forged_contract_address_placement_not_attributed_to_victim_pair in MR !750. Parser forged-attack tests 3/3.

AC3 (only the runtime-stamped emitter scopes): met. Every lifecycle path (fills/cancels/placements/claims, interleaved and columnar) goes through the reserved-only helper; grep confirms no production code scopes on the no-underscore key. No-regression test genuine_fill_with_both_contract_address_keys_attributes_to_pair passes. Parser suite 29/29.

Two things straight: (1) no live positive control — the fresh seed has zero lifecycle rows, so "a real fill attributes to its pair" is unit-proven, not live-proven; (2) direction 3 (factory provenance) is still a follow-up — a forged event now self-corrupts the attacker's OWN discovered pair, which clusters with the pair-trust work in #279/#286/#287, not a victim-targeting hole. The victim-targeting AC are met; pending MR !750, @PlasticDigits good to close once you're happy with the provenance follow-up tracking.

Verified the forgery vector is closed at the parser, with the attack demo + regression tests you asked for. Mapping the AC: AC1 (forged `contract_address = victim_pair` + `action = limit_order_fill` doesn't attribute a fill to the victim): met. `is_wasm_contract_addr_key` / `wasm_contract_addr` now match only the runtime-reserved `_contract_address`; the no-underscore form is data, never the emitter. The forged fill re-scopes to the attacker's own `_contract_address`, not the victim. Test `forged_contract_address_fill_not_attributed_to_victim_pair` passes and is non-vacuous (reverting the predicate makes it fail). AC2 (forged cancel/placement can't alter a victim's served lifecycle): met. Cancel was already covered (`forged_contract_address_cancel_not_attributed_to_victim_pair`). Placement was closed at source (same reserved-only predicate on the placement parse paths) but had no named test — added `forged_contract_address_placement_not_attributed_to_victim_pair` in MR !750. Parser forged-attack tests 3/3. AC3 (only the runtime-stamped emitter scopes): met. Every lifecycle path (fills/cancels/placements/claims, interleaved and columnar) goes through the reserved-only helper; grep confirms no production code scopes on the no-underscore key. No-regression test `genuine_fill_with_both_contract_address_keys_attributes_to_pair` passes. Parser suite 29/29. Two things straight: (1) no live positive control — the fresh seed has zero lifecycle rows, so "a real fill attributes to its pair" is unit-proven, not live-proven; (2) direction 3 (factory provenance) is still a follow-up — a forged event now self-corrupts the attacker's OWN discovered pair, which clusters with the pair-trust work in #279/#286/#287, not a victim-targeting hole. The victim-targeting AC are met; pending MR !750, @PlasticDigits good to close once you're happy with the provenance follow-up tracking.
PlasticDigits commented 2026-06-05 03:18:44 +00:00 (Migrated from gitlab.com)

mentioned in commit 223128fbda

mentioned in commit 223128fbdac55ae8b25aaf6ea3bf457778311077
PlasticDigits commented 2026-06-05 03:56:46 +00:00 (Migrated from gitlab.com)

Needs to be live proven.

Needs to be live proven.
PlasticDigits commented 2026-06-05 04:08:28 +00:00 (Migrated from gitlab.com)

mentioned in issue #311

mentioned in issue #311
PlasticDigits commented 2026-06-05 04:08:29 +00:00 (Migrated from gitlab.com)

marked as related to #311

marked as related to #311
PlasticDigits commented 2026-06-05 04:08:30 +00:00 (Migrated from gitlab.com)

mentioned in issue #316

mentioned in issue #316
Brouie commented 2026-06-05 06:52:09 +00:00 (Migrated from gitlab.com)

mentioned in merge request !775

mentioned in merge request !775
Brouie commented 2026-06-05 06:52:22 +00:00 (Migrated from gitlab.com)

Heads-up from working #316: the _contract_address scoping from this issue (e951e61) left one integration test red on main — tests/limit_order_parked_lifecycle.rs::park_event_then_claim_updates_db_and_api_filters. Its wasm_park_tx/wasm_claim_tx fixtures still emit the unreserved contract_address, so post-#285 the park/claim events don't match and the order stays active. The fixture sweep here got the parser unit tests but missed this one. Test-only fix (point the fixtures at _contract_address) in MR !775. Not reopening this — just connecting them.

Heads-up from working #316: the _contract_address scoping from this issue (e951e61) left one integration test red on main — tests/limit_order_parked_lifecycle.rs::park_event_then_claim_updates_db_and_api_filters. Its wasm_park_tx/wasm_claim_tx fixtures still emit the unreserved contract_address, so post-#285 the park/claim events don't match and the order stays active. The fixture sweep here got the parser unit tests but missed this one. Test-only fix (point the fixtures at _contract_address) in MR !775. Not reopening this — just connecting them.
PlasticDigits commented 2026-06-05 07:03:44 +00:00 (Migrated from gitlab.com)

mentioned in commit 2e67269718

mentioned in commit 2e67269718cc220bea1bdd762f7988117248709e
ghost1 commented 2026-06-05 09:49:44 +00:00 (Migrated from gitlab.com)

mentioned in commit bb8af7da19

mentioned in commit bb8af7da193e4325c9ee430ed93afc6f0f388b25
PlasticDigits commented 2026-06-05 10:05:46 +00:00 (Migrated from gitlab.com)

mentioned in merge request !787

mentioned in merge request !787
PlasticDigits commented 2026-06-05 10:05:57 +00:00 (Migrated from gitlab.com)

Verification complete (agent:verify)

Issue: https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/work_items/285

Parser fix on main verified. Added live-proof harness in MR !787.

Acceptance criteria

Item Result Evidence
AC1 — forged contract_address=victim + limit_order_fill does not attribute fill to victim PASS cargo test --lib "forged_contract_address|genuine_fill_with_both_contract_address" (4 tests)
AC2 — forged cancel/placement cannot alter victim lifecycle PASS forged_contract_address_cancel_not_attributed_to_victim_pair, forged_contract_address_placement_not_attributed_to_victim_pair
AC3 — only runtime _contract_address scopes lifecycle events PASS is_wasm_contract_addr_key → _contract_address only; limit_order_parked_lifecycle integration
Live positive control (per @PlasticDigits) PASS make verify-issue-285 live leg: hybrid swap → on-chain limit_order_fill with _contract_address=<pair> → indexer GET /api/v1/pairs/{pair}/limit-fills row (tx E168DBF8EE7695C5…)

Full run: make start && make wait-healthy && make deploy-local && make verify-issue-285 → 12 passed, 0 failed.

MR

Guardrails (verify script, L285 invariant doc, agent skill): https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/merge_requests/69

Direction 3 (factory provenance on discovery) remains follow-up on #279/#286/#287.

## Verification complete (agent:verify) Issue: https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/work_items/285 Parser fix on `main` verified. Added live-proof harness in MR !787. ### Acceptance criteria | Item | Result | Evidence | |------|--------|----------| | AC1 — forged `contract_address=victim` + `limit_order_fill` does not attribute fill to victim | **PASS** | `cargo test --lib "forged_contract_address\|genuine_fill_with_both_contract_address"` (4 tests) | | AC2 — forged cancel/placement cannot alter victim lifecycle | **PASS** | `forged_contract_address_cancel_not_attributed_to_victim_pair`, `forged_contract_address_placement_not_attributed_to_victim_pair` | | AC3 — only runtime `_contract_address` scopes lifecycle events | **PASS** | `is_wasm_contract_addr_key` → `_contract_address` only; `limit_order_parked_lifecycle` integration | | Live positive control (per @PlasticDigits) | **PASS** | `make verify-issue-285` live leg: hybrid swap → on-chain `limit_order_fill` with `_contract_address=<pair>` → indexer `GET /api/v1/pairs/{pair}/limit-fills` row (tx `E168DBF8EE7695C5…`) | **Full run:** `make start && make wait-healthy && make deploy-local && make verify-issue-285` → **12 passed, 0 failed**. ### MR Guardrails (verify script, L285 invariant doc, agent skill): https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/merge_requests/69 **Direction 3** (factory provenance on discovery) remains follow-up on #279/#286/#287.
ghost1 commented 2026-06-05 10:07:43 +00:00 (Migrated from gitlab.com)

mentioned in commit ce9040cb93

mentioned in commit ce9040cb936d4c4be9080a540e0bada13b3709eb
PlasticDigits commented 2026-06-05 10:08:10 +00:00 (Migrated from gitlab.com)

mentioned in merge request !790

mentioned in merge request !790
ghost1 commented 2026-06-05 11:01:34 +00:00 (Migrated from gitlab.com)

mentioned in commit 50f4417551

mentioned in commit 50f441755141564b0826ccc84dc802e5162bd731
PlasticDigits commented 2026-06-05 11:06:35 +00:00 (Migrated from gitlab.com)

mentioned in commit 856f024255

mentioned in commit 856f024255f28757f1cc799c12449e765c8d509b
PlasticDigits (Migrated from gitlab.com) closed this issue 2026-06-05 11:06:36 +00:00
ghost1 commented 2026-06-05 11:22:57 +00:00 (Migrated from gitlab.com)

mentioned in commit 0961244077

mentioned in commit 09612440778ccaa0c997b3b946d9c6d7fd5bd97e
PlasticDigits commented 2026-06-05 11:23:19 +00:00 (Migrated from gitlab.com)

mentioned in merge request !799

mentioned in merge request !799
PlasticDigits commented 2026-06-05 11:23:41 +00:00 (Migrated from gitlab.com)

Verification complete (agent:verify)

Issue: https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/work_items/285

Parser fix on main verified. Live positive control confirmed. Guardrails MR: !799 (supersedes conflicted !787).

Acceptance criteria

Item Result Evidence
AC1 — forged contract_address=victim + limit_order_fill does not attribute fill to victim PASS cargo test --lib forged_contract_address (3 tests); fill scopes to terra1attacker, not terra1victimpair
AC2 — forged cancel/placement cannot alter victim lifecycle PASS forged_contract_address_cancel_not_attributed_to_victim_pair, forged_contract_address_placement_not_attributed_to_victim_pair
AC3 — only runtime _contract_address scopes lifecycle events PASS is_wasm_contract_addr_key → _contract_address only; limit_order_parked_lifecycle integration
Live positive control (per @PlasticDigits) PASS make verify-issue-285 live leg: hybrid swap tx 605336BF908325DE… → LCD limit_order_fill with _contract_address=<pair> → indexer GET /api/v1/pairs/{pair}/limit-fills row

Full run: make setup-cloud-localterra && make verify-issue-285 → 12 passed, 0 failed.

Parser suite: cd indexer && cargo test --lib indexer::parser::tests → 32/32 passed.

MR

https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/merge_requests/81 — verify script, L285 invariant doc, agent skill, Cloud Agent sg docker fallback for live leg.

Direction 3 (factory provenance on discovery) remains follow-up on #279/#286/#287.

## Verification complete (agent:verify) Issue: https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/work_items/285 Parser fix on `main` verified. Live positive control confirmed. Guardrails MR: !799 (supersedes conflicted !787). ### Acceptance criteria | Item | Result | Evidence | |------|--------|----------| | AC1 — forged `contract_address=victim` + `limit_order_fill` does not attribute fill to victim | **PASS** | `cargo test --lib forged_contract_address` (3 tests); fill scopes to `terra1attacker`, not `terra1victimpair` | | AC2 — forged cancel/placement cannot alter victim lifecycle | **PASS** | `forged_contract_address_cancel_not_attributed_to_victim_pair`, `forged_contract_address_placement_not_attributed_to_victim_pair` | | AC3 — only runtime `_contract_address` scopes lifecycle events | **PASS** | `is_wasm_contract_addr_key` → `_contract_address` only; `limit_order_parked_lifecycle` integration | | Live positive control (per @PlasticDigits) | **PASS** | `make verify-issue-285` live leg: hybrid swap tx `605336BF908325DE…` → LCD `limit_order_fill` with `_contract_address=<pair>` → indexer `GET /api/v1/pairs/{pair}/limit-fills` row | **Full run:** `make setup-cloud-localterra && make verify-issue-285` → **12 passed, 0 failed**. **Parser suite:** `cd indexer && cargo test --lib indexer::parser::tests` → **32/32 passed**. ### MR https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/merge_requests/81 — verify script, L285 invariant doc, agent skill, Cloud Agent `sg docker` fallback for live leg. **Direction 3** (factory provenance on discovery) remains follow-up on #279/#286/#287.
ghost1 commented 2026-06-05 12:43:56 +00:00 (Migrated from gitlab.com)

mentioned in commit 65c07c1385

mentioned in commit 65c07c1385a976ba1aef5e4098b7dd8d72476a52
PlasticDigits commented 2026-06-05 13:06:30 +00:00 (Migrated from gitlab.com)

mentioned in commit 1d644f99d8

mentioned in commit 1d644f99d80117c569a389c580926b01082eb63b
PlasticDigits commented 2026-06-05 14:08:55 +00:00 (Migrated from gitlab.com)

mentioned in merge request !817

mentioned in merge request !817
ghost1 commented 2026-06-06 06:55:40 +00:00 (Migrated from gitlab.com)

mentioned in commit fec80e46ed

mentioned in commit fec80e46ed150a723abb0cfdbeb7943eb2a9d086
PlasticDigits commented 2026-06-06 06:57:53 +00:00 (Migrated from gitlab.com)

mentioned in merge request !823

mentioned in merge request !823
PlasticDigits commented 2026-06-06 06:58:13 +00:00 (Migrated from gitlab.com)

mentioned in issue #335

mentioned in issue #335
PlasticDigits commented 2026-06-07 12:14:16 +00:00 (Migrated from gitlab.com)

mentioned in issue #337

mentioned in issue #337
Brouie commented 2026-06-08 00:20:37 +00:00 (Migrated from gitlab.com)

mentioned in merge request !835

mentioned in merge request !835
ghost1 commented 2026-06-08 05:24:40 +00:00 (Migrated from gitlab.com)

mentioned in commit 06eb2d8bb5

mentioned in commit 06eb2d8bb5bd7a30fa9d33e87c5d319082f06e1f
PlasticDigits commented 2026-06-08 08:43:13 +00:00 (Migrated from gitlab.com)

mentioned in commit c9fa5ad7da

mentioned in commit c9fa5ad7da20c50a26d15e94ec9821c6afc9f6fb
PlasticDigits commented 2026-06-08 08:43:13 +00:00 (Migrated from gitlab.com)

mentioned in commit 53b8658c58

mentioned in commit 53b8658c5850c50e45fdd163758ea9978315fc56
PlasticDigits commented 2026-06-08 13:42:28 +00:00 (Migrated from gitlab.com)

mentioned in commit 59c1013758

mentioned in commit 59c1013758d0a0b64d25cd2d98656847d892356e
PlasticDigits commented 2026-06-08 13:42:28 +00:00 (Migrated from gitlab.com)

mentioned in commit 59c1013758

mentioned in commit 59c1013758d0a0b64d25cd2d98656847d892356e
PlasticDigits commented 2026-06-08 13:42:28 +00:00 (Migrated from gitlab.com)

mentioned in commit 8f0ca4009d

mentioned in commit 8f0ca4009d3de0758929779faf1aaa3703d3394a
PlasticDigits commented 2026-08-09 08:25:55 +00:00 (Migrated from gitlab.com)

mentioned in issue #509

mentioned in issue #509
PlasticDigits commented 2026-08-24 00:30:13 +00:00 (Migrated from gitlab.com)

mentioned in issue #613

mentioned in issue #613
PlasticDigits commented 2026-08-24 00:30:20 +00:00 (Migrated from gitlab.com)

mentioned in issue #614

mentioned in issue #614
PlasticDigits commented 2026-08-27 04:45:36 +00:00 (Migrated from gitlab.com)

mentioned in issue #684

mentioned in issue #684
PlasticDigits commented 2026-08-27 07:03:58 +00:00 (Migrated from gitlab.com)

mentioned in merge request !1188

mentioned in merge request !1188
PlasticDigits commented 2026-08-27 07:04:56 +00:00 (Migrated from gitlab.com)

mentioned in merge request !1189

mentioned in merge request !1189
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
code/cl8y-dex-terraclassic#285
No description provided.