# How the Office Action Response Mode Applies Relative Scoring Across Multiple Precedents

> Learn how the Office Action response mode uses relative scoring across precedents to rank arguments. Discover a unified approach to evaluating historical cases for patent disclosure skills.

- Repository: [handsomestWei/patent-disclosure-skill](https://github.com/handsomestWei/patent-disclosure-skill)
- Tags: how-to-guide
- Published: 2026-09-02

---

**The Office Action response mode normalizes raw similarity scores against the highest-scoring candidate and aggregates these relative scores across historical precedent cases to produce a unified ranking of response arguments.**

The `handsomestWei/patent-disclosure-skill` repository provides an automated toolkit for drafting patent Office Action responses by analyzing previously adjudicated cases. Central to this system is the **Office Action response mode**, which utilizes a **relative scoring** mechanism to ensure arguments retrieved from diverse precedent cases are evaluated on a common scale. This methodology enables the pipeline to fairly compare responses drawn from multiple sources, regardless of variations in original case strength or terminology.

## How the Office Action Response Mode Calculates Relative Scores

### Ingesting Precedent Cases via [`tools/oa/ingest_case.py`](https://github.com/handsomestWei/patent-disclosure-skill/blob/main/tools/oa/ingest_case.py)

The pipeline begins by transforming raw precedent documents into a structured format defined by the **OA case schema** ([`references/schemas/oa_case.schema.yaml`](https://github.com/handsomestWei/patent-disclosure-skill/blob/main/references/schemas/oa_case.schema.yaml)). The `ingest_case()` function in [`tools/oa/ingest_case.py`](https://github.com/handsomestWei/patent-disclosure-skill/blob/main/tools/oa/ingest_case.py) parses each historical case to extract the claim language, rejection type (e.g., 35 U.S.C. § 102 or § 103), and the specific arguments that successfully overcame the rejection. These structured records are persisted to enable downstream vectorization and retrieval.

### Vectorizing Legal Arguments with [`tools/oa/embed.py`](https://github.com/handsomestWei/patent-disclosure-skill/blob/main/tools/oa/embed.py)

Once ingested, legal arguments are converted into dense text embeddings using the `build_vector_store()` function in [`tools/oa/embed.py`](https://github.com/handsomestWei/patent-disclosure-skill/blob/main/tools/oa/embed.py). This module processes the structured case data and stores the resulting vectors in a persistent vector database, refreshed via [`tools/oa/rebuild_vectors.py`](https://github.com/handsomestWei/patent-disclosure-skill/blob/main/tools/oa/rebuild_vectors.py) whenever the precedent corpus is updated. Each embedding captures the semantic meaning of an argument, allowing the system to identify conceptually similar responses across different technical domains.

### Retrieving and Normalizing Candidates in [`tools/oa/playbook.py`](https://github.com/handsomestWei/patent-disclosure-skill/blob/main/tools/oa/playbook.py)

When a new Office Action rejection is submitted, the `OAResponsePlaybook` class in [`tools/oa/playbook.py`](https://github.com/handsomestWei/patent-disclosure-skill/blob/main/tools/oa/playbook.py) generates an embedding of the new rejection text and executes a nearest-neighbor search against the vector store. This retrieval yields a set of candidate arguments, each associated with a **raw similarity score** (cosine similarity).

To enable fair comparison across heterogeneous precedents, the system applies **relative scoring** by normalizing against the maximum raw score:

```python

# Simplified view of the algorithm implemented in playbook.py

max_score = max(candidate.score for candidate in candidates)

for c in candidates:
    c.relative_score = c.score / max_score   # yields a value in [0, 1]

```

This normalization ensures the highest-similarity argument for the current query receives a **relative score of 1.0**, with all other candidates expressed as a fraction of that peak value.

### Aggregating Scores Across Precedent Boundaries

Because the retrieval step may return arguments originating from *different* precedent cases, the algorithm groups candidates by their source case and **sums the relative scores** for arguments addressing the same rejection type. This aggregation rewards arguments that are both strongly similar to the current rejection and frequently validated across multiple historical cases. The final aggregated score reflects the combined weight of similarity and precedential frequency, producing a balanced ranking that surfaces the most robust response strategies.

## Implementing the Relative Scoring Pipeline

The following example demonstrates how to ingest precedents, build the vector index, and retrieve ranked responses using the relative scoring system:

```python
from tools.oa.playbook import OAResponsePlaybook
from tools.oa.ingest_case import ingest_case
from tools.oa.embed import build_vector_store

# 1️⃣ Load a set of precedent cases (JSON/YAML files)

precedent_paths = [
    "references/cases/example_precedent_1.yaml",
    "references/cases/example_precedent_2.yaml",
]
for p in precedent_paths:
    ingest_case(p)          # parses & stores the case

# 2️⃣ Build / refresh the vector store (once per dataset update)

build_vector_store()        # creates embeddings & persists them

# 3️⃣ Create a playbook for a new office‑action rejection

new_oa = {
    "rejection_type": "35 U.S.C. § 102(a)",
    "rejection_text": "Claims are anticipated by prior art document X."
}
playbook = OAResponsePlaybook(new_oa)

# 4️⃣ Retrieve ranked responses

ranked_responses = playbook.get_ranked_responses(top_n=5)

# 5️⃣ Inspect relative scores

for resp in ranked_responses:
    print(f"Score: {resp.relative_score:.2f} | Source: {resp.source_case}")
    print(resp.argument_text)
    print("-" * 40)

```

Executing this script prints arguments ordered by their **relative_score** (0.0 – 1.0). This value indicates how closely each argument aligns with the current rejection relative to the best match found in the entire precedent corpus.

## Core Files Driving the Relative Scoring System

| File | Purpose | Link |
|------|---------|------|
| [`tools/oa/playbook.py`](https://github.com/handsomestWei/patent-disclosure-skill/blob/main/tools/oa/playbook.py) | Implements the OA response mode, performs similarity retrieval, computes relative scores, and ranks responses. | [GitHub · playbook.py](https://github.com/handsomestWei/patent-disclosure-skill/blob/main/tools/oa/playbook.py) |
| [`tools/oa/embed.py`](https://github.com/handsomestWei/patent-disclosure-skill/blob/main/tools/oa/embed.py) | Generates text embeddings and builds the persistent vector store used for similarity search. | [GitHub · embed.py](https://github.com/handsomestWei/patent-disclosure-skill/blob/main/tools/oa/embed.py) |
| [`tools/oa/ingest_case.py`](https://github.com/handsomestWei/patent-disclosure-skill/blob/main/tools/oa/ingest_case.py) | Parses precedent case files into the internal schema and registers them for later lookup. | [GitHub · ingest_case.py](https://github.com/handsomestWei/patent-disclosure-skill/blob/main/tools/oa/ingest_case.py) |
| [`tools/oa/rebuild_vectors.py`](https://github.com/handsomestWei/patent-disclosure-skill/blob/main/tools/oa/rebuild_vectors.py) | Refreshes the vector store index when the precedent corpus changes. | [GitHub · rebuild_vectors.py](https://github.com/handsomestWei/patent-disclosure-skill/blob/main/tools/oa/rebuild_vectors.py) |
| [`references/schemas/oa_case.schema.yaml`](https://github.com/handsomestWei/patent-disclosure-skill/blob/main/references/schemas/oa_case.schema.yaml) | Defines the structure of a precedent case, including claims, rejections, and arguments. | [GitHub · oa_case.schema.yaml](https://github.com/handsomestWei/patent-disclosure-skill/blob/main/references/schemas/oa_case.schema.yaml) |
| [`references/schemas/oa_playbook.schema.yaml`](https://github.com/handsomestWei/patent-disclosure-skill/blob/main/references/schemas/oa_playbook.schema.yaml) | Schema for the playbook output, specifying the `relative_score` field and response format. | [GitHub · oa_playbook.schema.yaml](https://github.com/handsomestWei/patent-disclosure-skill/blob/main/references/schemas/oa_playbook.schema.yaml) |

## Summary

- **Relative scoring** normalizes raw cosine similarities by dividing each candidate’s score by the maximum score in the result set, producing a 0.0–1.0 scale.
- The normalization logic resides in [`tools/oa/playbook.py`](https://github.com/handsomestWei/patent-disclosure-skill/blob/main/tools/oa/playbook.py) within the `OAResponsePlaybook` class.
- Arguments are aggregated across multiple precedent cases by summing their relative scores, rewarding both high similarity and cross-case validation.
- The pipeline relies on [`tools/oa/ingest_case.py`](https://github.com/handsomestWei/patent-disclosure-skill/blob/main/tools/oa/ingest_case.py) for data parsing and [`tools/oa/embed.py`](https://github.com/handsomestWei/patent-disclosure-skill/blob/main/tools/oa/embed.py) for vector generation.
- Output schemas in [`references/schemas/oa_playbook.schema.yaml`](https://github.com/handsomestWei/patent-disclosure-skill/blob/main/references/schemas/oa_playbook.schema.yaml) formally define the `relative_score` field to ensure consistent downstream consumption.

## Frequently Asked Questions

### How does the relative scoring algorithm handle precedents with conflicting arguments?

When precedents contain contradictory arguments for the same rejection type, the relative scoring algorithm treats each argument as a separate candidate. Because scores are normalized per query rather than per precedent, arguments from conflicting cases compete on equal footing. The aggregation step sums scores within each source case, so a case with multiple strong, similar arguments will accumulate a higher total weight, but individual weak arguments from any source are dampened by the normalization factor.

### What is the difference between raw similarity and relative score in the OA playbook?

**Raw similarity** is the direct cosine similarity between the embedding of the new rejection text and the embedding of a historical argument, typically ranging between -1 and 1. The **relative score** is the raw similarity divided by the maximum raw similarity found in the current candidate set, resulting in a normalized value between 0 and 1. This relative metric allows practitioners to interpret candidate strength proportionally to the best available match for that specific Office Action.

### Can the relative scoring weights be customized for different rejection types?

The current implementation in [`tools/oa/playbook.py`](https://github.com/handsomestWei/patent-disclosure-skill/blob/main/tools/oa/playbook.py) applies uniform normalization across all candidates retrieved for a given query, regardless of rejection type. However, because the retrieval step filters candidates by rejection type (e.g., § 102 vs. § 103), the relative scoring is effectively scoped to subsets of precedents. Developers may extend the `OAResponsePlaybook` class to apply type-specific amplification factors to the `relative_score` field before aggregation if domain-specific weighting is required.

### Which schema defines the structure of the relative score output?

The [`references/schemas/oa_playbook.schema.yaml`](https://github.com/handsomestWei/patent-disclosure-skill/blob/main/references/schemas/oa_playbook.schema.yaml) file formally defines the playbook output structure, including the `relative_score` field. This schema ensures that every response object returned by the system contains a normalized floating-point value representing the argument’s weighted relevance, enabling consistent integration with external patent management systems.