# How the Figure Plan Scoring System Determines Which Images Are Included in Patent Disclosures

> Understand the figure plan scoring system for patent disclosures. Learn how relevance and quality metrics determine image inclusion with specific score thresholds for line-art and source materials.

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

---

**The figure plan scoring system in patent-disclosure-skill selects images based on composite scores calculated from relevance and quality metrics, with strict thresholds: 70 points for line‑art and 50 points for source materials.**

The `handsomestWei/patent-disclosure-skill` repository implements a deterministic, score‑driven pipeline that automates image selection for patent disclosures. This article examines how the composite scoring algorithm, qualification rules, and schema enforcement work together to filter images according to the figure plan scoring system.

## Composite Score Calculation

The scoring logic lives in [`tools/shared/image_gen.py`](https://github.com/handsomestWei/patent-disclosure-skill/blob/main/tools/shared/image_gen.py). The `composite_score()` function computes a figure's eligibility using a weighted formula:

```python
def composite_score(fig: dict[str, Any]) -> float:
    """0.5 * relevance + 0.5 * quality; else ``score``."""

```

When both **relevance** and **quality** fields are present, the system averages them (0.5 weight each). If either field is missing, the raw **score** field substitutes as the composite value. This design allows flexible scoring: human‑annotated figures use dual metrics, while automated pipelines can rely on a single score.

## Threshold Requirements by Image Type

The figure plan scoring system enforces category‑specific minimums through module‑level constants:

| Constant | Value | Applies To |
|----------|-------|------------|
| `MIN_LINEART_SCORE` | 70.0 | Technical line drawings (`kind == "lineart"`) |
| `MIN_SOURCE_SCORE` | 50.0 | CAD files, photos, and other source materials |

These thresholds are defined at lines 43–44 of [`tools/shared/image_gen.py`](https://github.com/handsomestWei/patent-disclosure-skill/blob/main/tools/shared/image_gen.py) and referenced throughout the qualification functions.

## Qualification Rules and Inclusion Logic

Three distinct qualification functions determine how figures enter the disclosure pipeline. Each applies category‑specific checks beyond the base score threshold.

### Existing Line‑Art Qualification

The `is_qualified_existing_lineart()` function (lines 94–102) requires:
- `kind == "lineart"`
- `role != "rejected"`
- Composite score ≥ 70
- Both `relevance` and `quality` ≥ 70 (when present)

Passing figures receive `use_in_disclosure: true` and bypass image generation entirely.

### Design Photo Qualification

For **design patents**, the `is_design_photo_for_disclosure()` function (lines 115–123) selects clean product photos:
- `kind == "photo_clean"`
- `role != "rejected"`
- Composite score ≥ 50

These images appear directly in the final disclosure for design patent cases, identified by `patent_type == "design"`.

### Source Candidate Filtering

The `is_source_candidate()` function (lines 138–146) identifies usable source materials for **img2img / txt2img** generation:
- `kind != "lineart"`
- `role != "rejected"`
- Composite score ≥ 50

Importantly, these candidates **never appear directly in disclosures**. They serve only as inputs to the generation pipeline.

## Image Selection Functions

The figure plan scoring system exposes three primary selection interfaces:

| Function | Purpose | Selection Criteria |
|----------|---------|-------------------|
| `qualified_lineart(plan, case_dir)` | Returns disclosure‑ready line drawings | All figures passing `is_qualified_existing_lineart` |
| `pick_design_photos(plan, case_dir)` | Returns design patent photos | Clean photos passing `is_design_photo_for_disclosure` |
| `pick_sources(plan, case_dir, limit=4)` | Returns generation inputs | Top‑ranked source candidates by kind bucket and descending composite score |

The source picker applies additional ranking logic at lines 56–69, grouping candidates by `kind` and selecting the highest‑scoring entries from each bucket up to the limit.

## Mode Decision and Pipeline Routing

The `decide_mode()` function (lines 184–199) orchestrates the final disclosure strategy based on available qualified images:

```python
def decide_mode(plan: dict[str, Any], case_dir: Path) -> dict[str, Any]:
    existing = qualified_lineart(plan, case_dir)
    sources = pick_sources(plan, case_dir)
    # ...

    if existing:
        mode = GEN_EXISTING          # use existing line-art directly

    elif sources:
        mode = GEN_IMG2IMG          # generate new line-art from sources

    else:
        mode = GEN_TXT2IMG          # fallback to pure text-to-image generation

```

This cascade ensures that **only qualified existing line‑art** skips generation. The figure plan scoring system prioritizes accuracy over convenience:宁可 trigger expensive generation than include borderline images.

## Schema Enforcement

The [`figure_plan.schema.yaml`](https://github.com/handsomestWei/patent-disclosure-skill/blob/main/figure_plan.schema.yaml) file formalizes the scoring rules at the data model level. Each figure entry must contain:

- `kind`, `role`, `score`, `use_in_disclosure` (lines 15–26)
- For inclusion: `kind: lineart` with `score >= 70` or both `relevance` and `quality` ≥ 70 (lines 72–79)

The schema's minimum‑score declarations mirror the code constants, creating redundancy that catches configuration drift.

## Practical Usage Examples

### Calculating Composite Scores

```python
from tools.shared.image_gen import composite_score

fig = {
    "kind": "lineart",
    "relevance": 78,
    "quality": 82,
    "score": 0   # ignored because relevance & quality are present

}

print(composite_score(fig))  # → 80.0

```

### Evaluating a Figure Plan for Disclosure

```python
import json
from pathlib import Path
from tools.shared.image_gen import (
    decide_mode, qualified_lineart, pick_design_photos
)

case_dir = Path("outputs/my_case")
plan = json.loads((case_dir / "figure_plan.yaml").read_text())

mode_info = decide_mode(plan, case_dir)

print("Chosen mode:", mode_info["mode"])
print("Line-art to include:", qualified_lineart(plan, case_dir))
print("Design photos:", pick_design_photos(plan, case_dir))

```

## Summary

- **Composite scoring** blends relevance and quality (0.5/0.5) or falls back to raw score
- **Thresholds are strict**: 70 points for line‑art, 50 points for sources
- **Three qualification paths** handle existing line‑art, design photos, and generation sources differently
- **Mode decision** routes to `GEN_EXISTING` > `GEN_IMG2IMG` > `GEN_TXT2IMG` based on availability
- **Schema and code redundancy** ensures consistent enforcement across the pipeline

## Frequently Asked Questions

### What happens if a line‑art image scores 69 on relevance but 85 on quality?

The composite score would be 77.0 ((69 + 85) / 2), meeting the 70‑point threshold. However, the individual component check in `is_qualified_existing_lineart()` requires **both** relevance and quality ≥ 70 when present. This image would be rejected despite the acceptable average because the relevance score falls below 70.

### Can source materials with scores below 50 ever appear in disclosures?

No. The `MIN_SOURCE_SCORE = 50.0` constant is enforced in `is_source_candidate()`, which gates all non‑lineart materials. Sub‑50 sources are excluded from both direct disclosure and the generation pool. The only path to disclosure for such materials would require prior regeneration into qualified line‑art.

### How does the system handle missing relevance or quality fields?

The `composite_score()` function detects missing fields and substitutes the raw `score` value. This allows backward compatibility with figure plans that only contain legacy scoring. The qualification functions then compare this single score against the appropriate threshold without additional component checks.

### Where are the threshold constants defined if I need to adjust them?

Both `MIN_LINEART_SCORE` and `MIN_SOURCE_SCORE` are module‑level constants at lines 43–44 of [`tools/shared/image_gen.py`](https://github.com/handsomestWei/patent-disclosure-skill/blob/main/tools/shared/image_gen.py). The [`figure_plan.schema.yaml`](https://github.com/handsomestWei/patent-disclosure-skill/blob/main/figure_plan.schema.yaml) file at [`references/schemas/figure_plan.schema.yaml`](https://github.com/handsomestWei/patent-disclosure-skill/blob/main/references/schemas/figure_plan.schema.yaml) (lines 72–79) contains parallel declarations that should be synchronized with any code changes to maintain schema validation consistency.