Skip to content

Slice 2: Mock Call, Real CRM — full implementation + audited (52/53 tasks done)#3

Merged
brettheap merged 60 commits into
mainfrom
002-mock-call-real-crm
May 25, 2026
Merged

Slice 2: Mock Call, Real CRM — full implementation + audited (52/53 tasks done)#3
brettheap merged 60 commits into
mainfrom
002-mock-call-real-crm

Conversation

@brettheap
Copy link
Copy Markdown
Contributor

@brettheap brettheap commented May 22, 2026

Slice 2 — Mock Call, Real CRM

Swap the Slice 1 mock CRM for real Dynamics 365 / Dataverse while keeping the call transport and persona mocked. Ships the full Spec Kit workflow (specify → clarify → plan → checklist ×13 → tasks → analyze ×5 → implement) plus a 10-expert swarm code-review pass with full remediation. Branch is fully audited and passes a clean /speckit-analyze (0 CRITICAL / 0 HIGH / 0 MEDIUM / 0 LOW).

What ships

  • DataverseWriteBackAdapter behind the unchanged Slice 1 WriteBackAdapter protocol — 4 operations (Phone Call activity, queue-status update, Task, write-back assembly), idempotency-key stamp + pre-query (FR-024), bounded transient retry (FR-023), If-Match/@odata.etag optimistic concurrency on the final PATCH (T045/Pass-1B).
  • DataverseQueueLoader behind the unchanged QueueItem contract — ExplicitId + NextReady selectors, deterministic next-ready tie-break, FR-009 empty-queue no-op vs T051 configured_campaign_not_found distinction.
  • OAuth2 client-credentials auth (httpx + Microsoft Entra ID) with redacted error formatters (tenant_id never leaks; FR-005 + T047).
  • Metadata discovery + per-run verification (FR-001/FR-002): discover-crm CLI command produces config/dataverse_mapping.json; every write-enabled run re-verifies live.
  • dry-run vs write-enabled run modes (FR-031, SC-013) — default dry-run produces planned-writeback artifacts with zero CRM writes; --write performs actual writes.
  • Resume coordinator (FR-023, SC-014) — run-crm --resume <session-id> replays only missing emit_* operations via idempotency pre-query short-circuit; fresh baseline at resume start for T045 conflict re-detection on pause-window human changes (CHK061).
  • T045 mid-run CRM-state conflict detection — captures last_session_id/status/preserve_if_present/@odata.etag baseline at load; raises CrmConflictError on any mismatch (including row-deletion); maps to exit_status="blocked" + block_reason="conflict_detected".
  • Default-on transcript redaction layer (FR-028..FR-030) — regex [REDACTED] policy with summary-only retention option.
  • FR-019/020 fixture pre-validation (resolves GitHub issue Transport: validate fixture at place_call time to avoid partial session state #2 — closed via T043) — malformed fixtures rejected before any session-state, queue-status, or attempt-count mutation.
  • Structured block_reason discriminator (Pass 1C) — eligibility | metadata | conflict_detected | permanent_other on CrmRunReport and ResumeReport.

Spec Kit artifacts (specs/002-mock-call-real-crm/)

  • spec.md — 35 FRs, 15 SCs, 6 user stories, with §Clarifications, §Definitions, §Edge Cases, and §Requirement Coverage Notes.
  • plan.md, research.md, data-model.md (incl. T050 state-machine spec), quickstart.md (T042 demo runbook).
  • 6 module contracts under contracts/ (incl. T049 run-report JSON schema in cli-slice2.md).
  • tasks.md53 tasks across 9 phases · 52 done · 1 deferred (T052 architectural follow-up).
  • 13 requirements-quality checklists under checklists/all 100% closed including reverification.md (72/72).

Implementation tally

Phase Tasks Status
1 Setup T001–T004
2 Foundational T005–T016
3 US1 MVP write-enabled T017–T023, T048
4 US2 dry-run T024–T027
5 US3 metadata block T028, T029a, T029b, T030, T051
6 US4 idempotency + resume + T045 conflict T031–T034, T045, T046
7 US5 fixture validation T035–T036
8 US6 redaction T037–T039
9 Polish T040–T044, T047, T049, T050, T051, T052 deferred

Code-review + remediation history (5 analyze passes + 1 swarm review)

Audit Findings Outcome
Post-analyze (2026-05-22) 0/0/1/5 Resolved inline
Re-analyze 0/0/1/5 Resolved inline
Post-completion (2026-05-24) 0/0/1/5 T051 + I2–I6 polish
Swarm code-review (10 experts) 0/9/26/25 Pass 1A–1D + Pass 2A–2C + Pass 3 (8 commits)
Post-remediation 0/0/1/3 Pass 4 (1 commit)
Final 0/0/0/0 Ship-ready

Test + lint

  • 763 tests pass (was 432 at branch start)
  • 2 pre-existing test_constitution_sync.py failures predate this branch and are out of Slice 2 scope (constitution-template-vs-test format drift)
  • ruff check + format: clean
  • Adapter coverage: 94% (combined unit + contract + integration); boundary test (T040) verifies SC-010 across 17 modules × 17 patterns = 290 parametrized tests

How to review

This PR is large by line count (~15,800 net additions across 99 files) because it ships a complete vertical slice + spec artifacts + 13 checklists + extensive tests. Suggested review order:

  1. specs/002-mock-call-real-crm/spec.md — the 35 FRs + 15 SCs are the contract.
  2. specs/002-mock-call-real-crm/contracts/cli-slice2.md — Run Report JSON schema + state-machine spec + exit-status mapping.
  3. src/opencloser/crm/dataverse/ — the SOLE location of Dataverse vendor detail (SC-010 enforced by tests/contract/test_boundary_isolation.py).
  4. src/opencloser/slice2/runner.py + slice2/resume.py — Slice 2 CLI-level coordination; the Slice 1 orchestrator is reused unchanged (FR-014).
  5. tests/contract/test_dataverse_adapter_contract.py (T017) — proves the adapter satisfies the unchanged Slice 1 crm-writeback.md contract for all 11 dispositions.
  6. tests/integration/test_us*_*.py — end-to-end per user story against the in-process Dataverse fake.
  7. specs/002-mock-call-real-crm/checklists/reverification.md — 72-item audit record; every gap was either closed inline or tracked as a numbered task.

Test plan

  • CI: ruff + pytest green (uv run ruff check src/ tests/ && uv run pytest)
  • Local: opencloser run-crm --queue-item-id <test-guid> produces planned writeback (dry-run default) against a verified mapping
  • Local: opencloser run-crm --write --queue-item-id <test-guid> writes one Phone Call activity + one queue PATCH + one Task to a dedicated test record in Dynamics
  • Manual: walk quickstart.md end-to-end (§3 discover → §5 dry-run → §6 write-enabled → §7 conflict/resume recovery → §8 cleanup)
  • Verify GH issue Transport: validate fixture at place_call time to avoid partial session state #2 closed (done via T043 on 2026-05-24)

Deferred follow-up (out of scope for this PR)

  • T052 — Persist planned-writeback.json sidecar BEFORE emit_* attempts, so a natural transient-exhaust failure leaves a replay-ready artifact. Documented in contracts/cli-slice2.md §Behavior — resume and pinned by test_us4_natural_transient_exhaust_yields_resume_needed.

🤖 Generated with Claude Code

Loading
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants