in reviewhumanPR #299Auth
[Fellowship Challenge] Lab: prevent a losing bidder from being paid for a supply-chain part it was not awarded
Submission for the Hexaware x Project NANDA Fellowship Technical Challenge
Author
@Philippe012
github profile →- Status
- In review
- Opened on
- Oct 1
- Branch
- challenge/philippe012-claim-jump
Description
The pitch.
Submission for the Hexaware x Project NANDA Fellowship Technical Challenge ## Gap In the Lab `supply_chain` scenario, the manufacturer awards each component through contract-net bidding, holds the price in escrow, and releases it when the part is delivered. The release goes to whichever supplier sends the `part_delivery` first; the sender is never compared with the recorded award. A supplier that lost the bid can therefore deliver anyway and be paid for the part. Town does not detect this today. The `milestones` stage checks that an escrow release exists for each awarded task, but not who received it or how much. `ledger_conserved` also passes, because the money is conserved even though it reaches the wrong party. The message is correctly signed by its real sender, so the auth layer accepts it as well. Reproduced on unmodified `origin/main` (stock manufacturer and validator, with one losing supplier added): ``` task_awarded supply-axle winner=axle-2 cents=450 escrow_released supply-axle to=axle-1 cents=450 verdict: PASSED ``` ## Layer and track - **Track:** Lab - **Contribution:** a new Lab scenario pair, `supply_chain_claim_jump` and its negative control `supply_chain_claim_jump_unguarded`, with a dedicated validator. - **Layers exercised:** coordination (contract-net award) and payments (escrow hold and release). Neither plugin is modified; the scenario tests how the two compose. The existing `supply_chain` validator is unchanged, so the evaluator version stays at `lab-0.2.6` and existing bundles replay as before. - The scenario and validator live inside the package rather than in a `nandatown new` scaffold, because validators loaded through `plugin_files` cannot be replayed by `nandatown verify` (it reports an evaluator replay mismatch). ## Fault A new supplier role, `claim_jumper`, bids normally and then, 1.6 s later, sends a `part_delivery` for the task whether or not it won. The scenario keeps the existing delay fault on the first `part_delivery`, so the winner's delivery arrives after the claim jumper's. ## Invariant For every awarded task, exactly one escrow release is made, to the awarded supplier, for the awarded amount. This is checked by a new `milestone_payee` stage. The validator also reuses the existing supply-chain stages (procurement, milestones, assembly order, customer settlement). A new `award_bound_manufacturer` role keeps the invariant under the fault. It pays only the awarded supplier, and any other delivery is refused and recorded as a `delivery_refused` event. A delivery that arrives before the task has been awarded is also refused; without that check, the run would crash when releasing an escrow that was never held. ## Bundle fingerprint Both bundles pass `nandatown verify` (hashes match and the evaluator reproduces the recorded result). - **Guarded run `sim-1fc720f85293`:** `sha256:f6d3f3a6b8f30dbf2b42e136a0c64cf3d223d0c23daba614b1f12dcd8d523757` - Negative control `sim-a9d8b1f36209`: `sha256:8afaa6d96d3119cff89ecaa8c2d744d7c6daafb2051f8862ffaebec7902bf32f` Key events from `nandatown replay`: ``` unguarded t=1.60 task_awarded supply-axle winner=axle-2, cents=450 unguarded t=2.40 escrow_released supply-axle to=axle-1, cents=450 guarded t=2.40 delivery_refused supply-axle from=axle-1, expected=axle-2 guarded t=2.80 escrow_released supply-axle to=axle-2, cents=450 ``` Lab reruns produce new run IDs and fingerprints with the same stage verdicts. A five-trial campaign of each scenario gave 5/5 passed (guarded) and 5/5 failed at `milestone_payee` (control); seed 7 gives the same verdicts as seed 42. ## Negative control Both scenarios use the same seed, fault and claim jumper; only the manufacturer differs. | Scenario | Manufacturer | `supply-axle` paid to | `milestones` | `milestone_payee` | Verdict | |---|---|---|---|---|---| | `supply_chain_claim_jump` | award-bound | axle-2 (awarded) | …
Try it
Open PR on GitHubView diffCheckout locally
git fetch origin pull/299/head:pr-299
git checkout pr-299