Skip to content

Repository files navigation

Tarmac

✈️ Tarmac

Five agents fight over nine seats so the right people fly — an airline irregular-ops society that beats a single planner, provably.

Tarmac — five agents fight over nine seats so the right people fly



Live Live on Alibaba Function Compute Pitch Deck Watch Demo Devpost Demo Path QwenCloud Hackathon


Python Tests Coverage CodeQL License: MIT CI

Track 3: Agent Society. An airline irregular-operations society where the conflict is the architecture: Rebooking, Crew-Legality, Gate/Ground, Hotel, and Passenger-Advocate agents hold genuinely opposed objectives and negotiate over revocable claims on a row-locked seat ledger (sealed-bid in contested rounds). A Duty-Manager mediator resolves mechanically-detected deadlocks with Ed25519-signed, regulation-cited rulings — and an ablation benchmark proves the society beats a single planner, the exact "measurable efficiency gain over single-agent baselines" the track asks for.

A 12-year-old flying alone watches the DEPARTED board go red at 6 PM. Behind a door, one dispatcher with two phones is deciding whether she or the transplant cooler gets the last seat to Denver.


📊 The one number

On the frozen storm_dfw storm (180 displaced passengers, 139 legal seats), measured across 10 seeds:

Single planner Full society
Protected passengers stranded (medical courier, minor, wheelchair, tight connections) 17 3
Special-needs SLA met 0% 100%
Tight connections saved 0 9
Crew duty violations (tested invariant I2) 1 0

Seat supply is physically fixed, so raw strandings barely move — the society's win is in who flies. The single planner seats a flexible high-fare passenger on the last compliant nonstop while stranding the courier; the society doesn't.


🚀 Quickstart (offline, zero keys)

python3.12 -m venv .venv && ./.venv/bin/pip install -e ".[dev]"

./.venv/bin/tarmac run --scenario storm_dfw --seed 7  # watch the society negotiate
./.venv/bin/tarmac bench                              # the ablation table
./.venv/bin/tarmac verify-log runs/…/run.db           # re-check invariants I1–I5
./.venv/bin/python scripts/verify_offline.py          # zero-key judge path (exit 0)
./.venv/bin/python examples/meeting_rooms.py          # the protocol, non-airline, 20 lines

Everything above runs against deterministic policy agents — no network, no API key, byte-identical every time. Add --live (and DASHSCOPE_API_KEY) to swap in the real Qwen agents.

☁️ Deployed on Alibaba Cloud

Tarmac runs live on Alibaba Cloud Function Compute — a managed python3.10 runtime in ap-southeast-1, deployed straight from source (WSGI, no container registry):

https://tarmac-xceukceokg.ap-southeast-1.fcapp.run

Endpoint What it does
/verify Re-verifies the committed live Qwen run (qwen3.7-plus roles + qwen3.7-max mediator, 324-entry hash-chained log) byte-for-byte, in the cloud — chain, I5 replay, I1 capacity/exclusivity, I2 crew-duty, I3 cited rulings and I4 sealed-bid reveals all PASS
/run?scenario=storm_dfw&seed=7 Runs a fresh deterministic society on demand, returns the manifest + hash
/health Liveness probe ({"status":"ok"})

The same invariant-checked replay that runs offline (tarmac verify-log) also runs server-side on Alibaba Cloud, against a real live-Qwen run committed at docs/proof/. Deploy config lives in infra/fc/.

✅ Testing & CI

330 tests, all green, 100% coverage (./.venv/bin/pytest --cov=tarmac_society), in ~5 seconds:

============================= 330 passed in 5.56s ==============================

They cover the ledger's locking + double-claim rejection, sealed-bid commit→reveal with mismatch rejection, the deadlock detector on synthetic wait-for graphs, credibility-currency math, the mediator ruling flow, the invariants I1–I5, and the fixture guarantee that storm_dfw always produces ≥1 genuine deadlock.

# ── Code Quality ────────────────────────────
ruff check .                                   # lint
mypy src                                       # type check
pytest --cov=tarmac_society --cov-report=term  # unit tests + coverage

# ── Offline / zero-key judge path ───────────
python scripts/verify_offline.py               # society run + I1-I5 replay, exit 0

# ── Security ─────────────────────────────────
pip-audit                                      # dependency vulnerability scan

A GitHub Actions pipeline (.github/workflows/ci.yml) runs all of the above on every push/PR — this is a CLI/library, not a web app, so the harness substitutes a deterministic offline-replay gate for the browser E2E/Lighthouse stages a frontend project would run:

Layer Tool Status
Code Quality ruff + mypy ✅
Unit Testing pytest (100% coverage, 330 tests) ✅
Offline Verification scripts/verify_offline.py (I1–I5 replay, zero network) ✅
Security (SAST) CodeQL (Python) ✅
Security (SCA) Dependabot (pip + github-actions) + pip-audit ✅
Secret Scanning TruffleHog ✅
Build Verification python -m build + wheel install + CLI smoke test ✅

📊 The committed ablation

Same storm, three conditions, 10 seeds, offline & deterministic (docs/BENCH.md, regenerate with tarmac bench):

Metric Single planner Society − mediator Full society
Protected pax stranded (SLA-failed) (↓ better) 17 14 3
Stranded overnight (no seat) (↓ better) 52 [50–53] 96 [81–109] 50 [49–52]
Tight connections saved (↑ better) 0 3 9
Special-needs SLA met (%) (↑ better) 0.0 0.0 100.0
Crew duty violations (↓ better) 1 0 0
Rounds to quiescence (↓ better) 1 6 5
Contest stake (credibility) (↓ better) 0 60 40

The Society − mediator column is the point: strip out adjudication and the society is worse than a single planner (96 stranded), because contested claims get quarantined at the round cap with no one to rule. The mediator is load-bearing, not decorative.

🏗️ How it works

flowchart TB
  SC["storm_dfw fixture — 180 pax, 139 legal seats"] --> ORCH["round scheduler"]
  ORCH --> AG["5 role agents — private objectives"]
  AG <--> T{{"Qwen transport"}}
  T --> POL["Policy agents — deterministic, offline default"]
  T --> LLM["LiveQwen agents — qwen3.7-plus / qwen3.7-max"]
  AG -->|"sealed-bid commit → reveal (mismatch rejected, I4)"| LED[("ClaimLedger — SQLite row locks, capacity + exclusivity, I1")]
  LED -->|"deadlock: wait-for cycle / contested ≥2 rounds"| MED["Duty-Manager mediator<br/>Ed25519 ruling, cites a reg (I3)"]
  MED --> LED
  LED --> CH["hash-chained decision log → replay = identical manifest (I5)"]
  ORCH -.-> BN["ablation_bench.py — single vs society vs no-mediator"]
Loading

As built = offline uses deterministic policy agents (genuinely negotiate/deadlock/resolve on the fixture); live mode swaps in Qwen LLM agents behind DASHSCOPE_API_KEY (a real live run is committed at docs/proof/). Storage is SQLite; deployed live on Alibaba Function Compute (infra/fc/). Plain-text view below.

storm fixture ─▶ round scheduler ─▶ 5 role agents (private objectives)
                                       │  sealed-bid commit  SHA256(claim‖nonce)
                                       ▼  reveal (mismatch → rejected, I4)
                              ClaimLedger  (SQLite row locks, capacity + exclusivity, I1)
                                       │
                              DeadlockDetector  (wait-for cycle / contested ≥2 rounds)
                                       ▼
                              Duty-Manager mediator  → Ruling (Ed25519-signed, cites a reg, I3)
                                       ▼
                              hash-chained decision log  → replay reproduces the manifest (I5)
  • Claims are function calls, not sentences — a claim is a typed mutation against a ledger with real row-level locking, so contention has physics (two threads racing the last seat: exactly one wins — tested).
  • Sealed bids (SHA256(claim‖nonce)) mean rival agents can't adapt a bid after seeing another's; the ledger rejects any reveal that doesn't re-derive its digest.
  • Deadlock is mechanical — a wait-for cycle or a resource contested ≥2 rounds — so mediation is triggerable, never vibes-based.
  • Every ruling is signed and cited — a portable artifact: with the public key you can verify what was decided and on what regulation without trusting the DB.
  • Credibility currency bounds argument economically: contesting costs points, winning refunds + a premium, losing burns them — no infinite loops.

The negotiation core ships as tarmac-society, a domain-agnostic library (ClaimLedger, DeadlockDetector, Commitment, Mediator, Society, verify_log). examples/meeting_rooms.py reuses it for room booking in 20 lines.

🧩 Why only Qwen Cloud

Qwen surface What it buys the society Without it
qwen3.7-plus × 5 role agents persona-stable objectives across ~60 turns/run, cheap enough to measure frontier pricing makes a benchmarked society unaffordable
qwen3.7-max + thinking (mediator) adjudicating 5 conflicting position papers with citations plus-tier rulings split the difference and break duty clocks
structured output (Claim/Position/Ruling) the ledger executes claims mechanically; malformed = rejected free-text negotiation → nothing lockable, auditable, replayable
function calling (ledger ops) typed state mutations with row locks "I take seat 14C" has no physics
context cache (shared disruption prefix) the 4k-token storm prefix reused every turn ~10× token cost; the ablation dies
Batch API 60-run ablation offline at −50% the track's benchmark costs more than iterating is worth
text-embedding-v4 regulation-passage retrieval so rulings cite sources uncited rulings are vibes with a signature

Take Qwen Cloud out and Tarmac still runs — but it can no longer be measured, and an unmeasured agent society is exactly the group-chat demo this track is drowning in. The transport is swappable (FakeQwen ↔ LiveQwen); every other part — sealed bids, ledger physics, deadlock detection, signing, logging — is identical between offline and live.

The LiveQwen DashScope integration is not vaporware behind a flag: 19 deterministic tests (tests/test_qwen_transport.py, a stub OpenAI-shaped client) drive the real wire path offline — the qwen3.7-plus / qwen3.7-max model routing, the embedded-JSON-schema structured-output contract, the single reject-and-retry on invalid JSON, the enable_thinking flag on the mediator, per-agent claim/position filtering, and text-embedding-v4 batching. Flipping on --live executes that already-verified path; it only adds tokens, not new code. The one thing offline can't show is a live model's judgement — so we ran it: a real DASHSCOPE_API_KEY end-to-end run is committed at docs/proof/live_run.db (324 entries, qwen3.7-plus roles + qwen3.7-max mediator, all invariants PASS) and replays byte-for-byte, both locally and on the live Alibaba Function Compute deploy.

📋 Status — honest

Area State
Negotiation protocol, ledger, deadlock, mediator, signing, chain-log Done & tested (330 tests)
storm_dfw fixture + generator + committed fixtures/storm_dfw_seed7.json Done, deadlock guaranteed
Offline society (deterministic policy agents) Done — the default; no key, byte-stable
Ablation bench (3×10) + verify_offline + readiness check Done, table committed
Live Qwen agents (qwen3.7-plus / qwen3.7-max / text-embedding-v4) Done — real end-to-end live run committed. docs/proof/live_run.db is a fully live society run (qwen3.7-plus roles + qwen3.7-max mediator, 324 entries, all invariants PASS, replays byte-for-byte). Plus 19 deterministic wire-path tests behind DASHSCOPE_API_KEY (--live).
Alibaba Cloud deployment Deployed — live on Alibaba Cloud Function Compute (managed python3.10): /verify re-checks the live Qwen run in the cloud, plus /run + /health. Config in infra/fc/; an ECS runbook alternative is in infra/ecs/setup.md.
Ops-board UI Deferred — a static runs/<id>/report.html transcript is a nice-to-have, not shipped

Limitations. Tarmac is a simulator: synthetic reservation data, one curated storm (plus a seeded generator). It is decision-support and rehearsal, not a live GDS integration. LLM nondeterminism in live mode is bounded (temp 0.2, seeded, medians of 10) but not eliminated; the offline path is fully deterministic.

🤝 Contributing

Issue/PR templates, a Code of Conduct, and a security policy live under .github/. See .github/CONTRIBUTING.md for the dev-setup and pre-PR checklist.

📄 License

MIT © 2026 Edy Cu. Built solo in one day of a multi-project sprint.

🏷️ Versioning

This project uses Semantic Versioning with fully automated version management driven by Conventional Commits — the version is never edited by hand.

Commit type Bump Example
fix: … patch 1.0.0 → 1.0.1
feat: … minor 1.0.0 → 1.1.0
feat!: … or BREAKING CHANGE: footer major 1.0.0 → 2.0.0

python-semantic-release keeps the version in sync across pyproject.toml and src/tarmac_society/__init__.py.

  • In CI/CD: Stage 6 of the pipeline (.github/workflows/ci.yml) runs on every push to main, computes the next version from the commits since the last tag, then commits + tags it automatically.
  • Locally:
    pip install -e ".[release]"
    semantic-release version    # compute + apply the next version and tag

About

✈️ Agent society for flight-disruption rebooking: sealed-bid negotiation, mediator, Ed25519-signed rulings · Qwen Cloud hackathon (Track 3)

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

3 stars

Watchers

0 watching

Forks

Releases

Used by

Contributors

Languages