Reworks the P1 sim so the four §7.1 exit criteria are demonstrated against the ACTUAL mechanic, not a model (resolves the verifier's "sim models the ledger, not the LangGraph integration" finding). - New tests/sim/test_p1_graph_integration.py drives the real agent_team.graph StateGraph (interrupt/Command(resume)) + the real langgraph SqliteSaver checkpointer + the committed pending_questions compare-and-set, proving: (a) suspend survives a simulated restart (drop saver/conn, rebuild over the same checkpoint DB) and resumes; (b) duplicate answer loses the CAS and the graph never double-advances; (c) a post-deadline answer loses to expire and the task is not resumed; (d) two concurrent tasks resume to the correct thread, with a turn-guarded no-double-apply check. - graph.py: derive a STABLE question_id from uuid5(thread_id, turn). The clarifier node replays on resume, so the prior fresh-uuid id changed between the delivered/ledgered question and the qa_history entry — breaking the §3.3.1 identity contract. Now the delivered id == ledger key == history entry (unit-tested in test_graph.py). - harness._connect() now uses the committed schema.connect() (WAL + busy_timeout) instead of a raw sqlite3.connect, so concurrent responders genuinely serialize; the criterion-(d) concurrency test no longer swallows OperationalError (it asserts zero errors + exactly one CAS winner). - requirements.txt: pin langgraph-checkpoint-sqlite==3.1.0 (design D9 durable checkpointer), now exercised by the integration test. Full suite: 564 passed; ruff + format clean. |
||
|---|---|---|
| .. | ||
| agent_team | ||
| ci | ||
| tests | ||
| .gitignore | ||
| README.md | ||
| run-team.py | ||
agent-team — R720 Plane-2 FOUNDATION
Pre-deployment scaffolding for the R720 agent-team SDLC pipeline (design:
../docs/r720-agent-team-design.md). This commit ships the Plane-2
FOUNDATION layer only — the durable, transport-agnostic contracts the leaf
builders import verbatim. Nothing here is provisioned, scheduled, or wired to
live infrastructure.
Status: FOUNDATION modules only. No coordinator, no transports' concrete adapters, no CI workflow, no provisioning. Those are later phases (§7).
Layout
agent-team/
agent_team/ # importable package (snake_case)
state_store.py # §6.7 atomic write + integrity-checked read
billing.py # §3.1 claude_invoke billing-mode seam
task_model.py # §3.3 TaskRecord / Phase / PipelineState
db/
schema.py # §3.3.1/§6.7 SQLite DDL + connect/init/migrate
schema.sql # raw DDL, mirrors schema.py verbatim
transport/
base.py # §3.3.1 Transport ABC + QuestionSet/NormalizedAnswer
tests/ # pytest unit tests, one module per source module
The top directory is kebab-case (agent-team/); the importable package is
snake_case (agent_team/), per the engineering handbook.
Modules (contracts)
| Module | Design ref | What it provides |
|---|---|---|
state_store |
§6.7 | atomic_write(path, data) (write-temp → fsync → rename), read_checked(path, *, schema_version) (schema-version + content-hash integrity check, raises IntegrityError), compute_content_hash(data). Pure stdlib; no other agent_team deps. |
db.schema |
§3.3.1, §6.7 | SCHEMA_VERSION, PENDING_QUESTIONS_DDL, BUDGET_LEDGER_DDL, connect() (WAL + foreign_keys + busy_timeout), init_db(), migrate(), and the BEGIN IMMEDIATE compare-and-set helpers (answer_question/expire_question/supersede_question). SQL DDL lives only here. |
billing |
§3.1 | BillingMode{SUBSCRIPTION,API,BEDROCK}, claude_invoke(prompt, *, mode=None, **kw) -> ClaudeResult, resolve_mode(config). Single seam; subscription mode pops any stray ANTHROPIC_API_KEY so OAuth can't be overridden. |
transport.base |
§3.3.1 | Transport ABC (post_question → channel_ref; parse_answer → (question_id, answer, via)), QuestionSet, NormalizedAnswer. Transport-independent; Slack/GitHub/Claude-Code adapters subclass in the leaves. |
task_model |
§3.3 | TaskRecord, TaskStatus, Phase{INTAKE…DONE}, new_thread_id(), PipelineState TypedDict (LangGraph state schema), JSON serialization helpers. Pure model, no I/O. |
Durable human-in-the-loop (§3.3.1)
The pending_questions ledger is the single durable source of truth for the
question lifecycle. Every race (duplicate answers, transport redelivery,
answer-vs-timeout) resolves via one atomic compare-and-set against the status
column, run inside a BEGIN IMMEDIATE transaction so concurrent responders are
serialized — first-answer-wins (rowcount == 1), late/duplicate ignored
(rowcount == 0). The LangGraph SqliteSaver checkpointer creates its own
tables against the same DB file.
Running the tests
cd agent-team
python3 -m pytest tests/ -q
tests/conftest.py puts the package on sys.path, so no install is required.
Not in this commit (later phases)
Coordinator/brain, concrete Slack/GitHub/Claude-Code transport adapters, the
CI apply/verify workflow (§3.3.2), step-ca / Roles Anywhere, scheduling, and
the operator CLI (run-team.py). See ../docs/r720-agent-team-design.md §7
for the phased rollout. Secrets are never committed.