Skip to content

feat(reporting): scope rollup comparison — project↔project, package↔package, issuance↔issuance over shared sections #393

Description

@thewrz

Why

POST /reports/compare compares exactly two sections. Real questions are scope-level: two campuses ("how does Building A's project differ from Building B's?"), two packages ("Underground vs Core & Shell — where do shared divisions diverge?"), two issuances of the same package, or a package's live state vs its last issuance. Today an agent must discover the shared sections itself and orchestrate N calls — and nothing reports the membership delta (sections present in only one scope), which for packages is half the answer.

What

  1. New endpoint POST /reports/compare-scope (separate operationId — the per-section endpoint stays untouched): sources = exactly two scope refs, each { projectId } | { packageId } | { revisionId } (revision refs need feat(reporting): frozen revision trees as comparison sources — polymorphic compare refs + freeze-time origin embedding (ADR required) #392's frozen loader).
  2. Section pairing: resolve each scope to its member sections (project TOC via project_specs, package via package_specs, revision via package_revision_specs), pair by canonical section number (lib/section-number.ts grammar), report the membership delta (onlyIn per scope) as first-class output.
  3. Per-pair comparison: run the existing aligner per shared section (reusing feat(reporting): structural alignment fallback + differences filter + summary — compare independently-ingested specs #384's summary + feat(reporting): frozen revision trees as comparison sources — polymorphic compare refs + freeze-time origin embedding (ADR required) #392's loaders); emit summary rows only (per-section { rows, aligned, identical, differing } + alignedBy) — token-conscious by design, the full matrix stays behind the per-section endpoint (drill-down refs echoed per row).
  4. Overall rollup: totals across sections + membership counts, so an agent can answer "how different?" in one call.
  5. Deterministic ordering (section-number sort); same alignment option plumbed through; differences filter analog (only sections with differences).

OpenAPI ↔ MCP contract lockstep

New endpoint + schemas ⇒ openapi.yaml AND a new compare_scopes MCP tool (tier read) in contract-map.ts in the same PR; contract gates enforce parity.

Prior art / cross-links

Non-goals

  • Client↔client or cross-scope-kind heuristics beyond the three ref kinds; PDF; demo UI (next issue).

Acceptance

  • Two projects sharing K sections → K summary rows + correct onlyIn lists; package↔package respects package membership (not whole project); revision↔revision uses frozen trees; empty intersection → valid report with empty rows + full membership delta; determinism regression.
  • Unit + integration + both contract gates green.

Sequenced after #392.

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    • Status
      Ready

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions