Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions .claude/preferences/editorial-preferences.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,17 @@ This file captures Frances's editorial judgment — corrections made to Claude's

---

## Parameter descriptions

**Copy existing wording precisely when a parameter is already documented elsewhere.**
When a parameter appears in another SenseML method's docs and the underlying implementation is the same, copy the description verbatim. Only drop clauses that are structurally specific to the other method's context (e.g., a conditional "If you use the Width or Height parameters..." that doesn't apply). Do not paraphrase, tighten, or rewrite.

*Why:* Rewriting introduces subtle differences that require correction. The wording is already right — use it.

*Example:* `percentOverlapX` / `percentOverlapY` already documented in `intersection.md` with confirmed shared implementation (`getLinesInRegion` in `method-helpers.ts`). Required two interruptions to get Claude to stop paraphrasing. (2026-06, branch `region`)

---

## Examples

**Evaluate updating existing examples before authoring new ones**
Expand Down
4 changes: 4 additions & 0 deletions .claude/sessions/2026-07-02-region-asImage/checklist.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Checklist — region: asImage + percentOverlapX/Y

- [x] Investigate Vale style check failure: `style 'Google' does not exist on StylesPath` — fixed: Google package was never synced; ran `vale sync` to download it, added `asImage`/`percentOverlapX`/`percentOverlapY`/`includeImages`/`isAbsoluteOffset` to vocab accept list
- [x] Decide whether `asImage` needs a full example — no example needed (user decision)
100 changes: 100 additions & 0 deletions .claude/sessions/2026-07-02-region-asImage/frances-edits.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
# Frances's edits — region/asImage session (2026-07-02)

Consolidated diff: `aacc76421..bd7a671a4` (4 commits)

Files touched: `document-range.md`, `region.md`, `query-group.md`, new `concepts/images.md`

---

## Frances's stated reasons

1. Query Group and Document Range both have image-related parameters — they were siloed from each other and from the new `asImage` Region parameter.
2. Three methods now support image-related capabilities. That's enough to warrant surfacing image processing as a concept topic. Previously only Document Range supported it.

---

## Changes by file

### NEW: `docs/Senseml reference/concepts/images.md`

Created from scratch. A 2-column lookup table (Use case | Method) with three rows:

| Use case | Method |
|---|---|
| Use an LLM to extract structured data from an image. For example, extract facts about a photo of a building, such as its color and whether it's multistory-story or single-story. | use the [Query Group](doc:query-group) method with the Multimodal Engine parameter configured |
| Extract an image from a known region as an encoded string. For example, use this option when your documents contain complex charts, from which neither LLM-based nor layout-based methods can reliably extract structured data. Extract the chart as an image and show it to human to interpret. | use the [Region](doc:region) method with the As Image parameter configured |
| Search for non-labeled, non-text images in a range. For example, search for unlabeled photos of houses in a real estate document, and extract the images' coordinates. This option returns images' coordinates, which you can then use to render the images yourself. | use the [Document Range](doc:document-range) method with the Include Images parameter configured |

Plus a Notes section with:
- Coordinate conventions (top-left origin, not bottom-left as in PDF.js; in inches; ordered clockwise from top-left)
- "This topic is about processing non-text images. For information about processing text images, see [OCR](doc:ocr)."

Title of page: "Image processing"

---

### `document-range.md`

**`includeImages` parameter description** — from:
> "Returns the zero-indexed page number and coordinates of regions containing images in the document range. **Notes**: If you set `true`, also set`"type": "images"` in the `field` object (see Examples section for an example). Returns image region coordinates, not image bytes or text lines. To extract structured data from images, see the [Query Group](doc:query-group) method and configure the Multimodal Engine parameter."

To:
> "If true, Sensible searches for images in the document range and returns the zero-indexed page number and coordinates of regions containing images in the range. **Notes**: If you set `true`, also set `"type": "images"` in the `field` object (see Examples section for an example). Returns image region coordinates, not image bytes or text lines. Sensible doesn't support this parameter for scanned documents. For rendering the image coordinates returned by this parameter, see [Notes](doc:document-range#notes). For alternatives to this parameter, see [Image processing](doc:images)."

**Notes section heading** — from `## Extracting images` to `## Extracting images from Document Range coordinates`

**Notes section body** — from:
> "The Document Range supports extracting non-text images that you can then render. For example, extract photos of buildings embedded in an inspection report and save them to a backend. It doesn't support extracting structured data from the images.
>
> **Note:** To extract structured data from an image, use the [Query Group](doc:query-group) method with the Multimodal Engine parameter configured. For example, extract facts about the building, such as whether it's multistory-story or single-story.
>
> To extract images, set `"includeImages":true` for the Document Range method. Sensible returns the image region coordinates rather than the actual encoded bytes of images. If you want to extract the images themselves, you can use a PDF library in your chosen programming language to follow these general steps:
> * Render the page containing the image to a bitmap. Page numbers are zero-indexed in the Sensible output.
> * Convert Sensible's coordinates for the image region to pixel per inch (PPI) coordinates. Sensible's region coordinates follow these conventions:
> * they're in reference to a 0.0 origin at the top left corner of the page (not the bottom left origin, as is for example the convention with the popular PDF.js library)
> * they're in inches (to convert inches to pixels, multiply the inches coordinates by your PPI setting...)
> * they're ordered clockwise from top left: (top left), (top right), (bottom right), (bottom left)"

To:
> "When you use the Document Range's Include Images parameter to search for images in a range, the Document Range returns the coordinates of images it finds rather than the encoded bytes of the image. If you want to extract the images themselves, use a PDF library in your chosen programming language to follow these general steps:
> * Render the page containing the image to a bitmap. Page numbers are zero-indexed in the Sensible output.
> * Convert Sensible's [coordinates](doc:image#coordinate-conventions) for the image region to pixel per inch (PPI) coordinates.
> * Extract a partial bitmap defined by the PPI coordinates of the image from the rendered page.
> * Encode the bitmap to bytes in the image format of your choice."

(Coordinate conventions bullets removed — now live in `images.md` and linked via `doc:image#coordinate-conventions`.)

**Parameter table** — column widths normalized (no content changes to other rows).

---

### `region.md`

**`asImage` parameter description** — from:
> "When true, Sensible renders the region's bounding rectangle from the PDF page and returns it as a `data:image/png;base64,...` string. Use this to capture visual content — such as signatures, stamps, or checkboxes — instead of extracting text."

To:
> "When true, Sensible returns the region as an image. Sensible returns the image's [coordinates](doc:images#notes) and its base64-encoded string, for example, `data:image/png;base64data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAABMgAAABaCAYAAA....` Use this option to capture visual content instead of extracting text. For example, use this option when your documents contain complex charts, from which neither LLM-based nor layout-based methods can reliably extract structured data. Extract the chart as an image and show it to human to interpret. For alternatives to this parameter, see [Image processing](doc:images)."

---

### `query-group.md`

**Parameter table** — column widths normalized (no content changes to existing rows).

**`multimodalEngine` description** — added at end:
> "For alternatives to the Multimodal parameter, see [Image processing](doc:images)."

---

## Speculated reasons (beyond stated)

**Coordinate conventions consolidated into `images.md`** — previously lived only in `document-range.md`. Now that Region's `asImage` also returns coordinates, a single canonical home that both methods can link to was needed. The concept topic created that home.

**`asImage` description rewrite: mechanism-first → scenario-first** — Claude's original description led with the implementation ("renders the bounding rectangle... returns it as a data:image/png;base64,... string"). Frances rewrote to lead with what Sensible does from the user's perspective, consistent with her stated editorial preference for scenario-first framing. She also replaced the specific use-case list (signatures, stamps, checkboxes) with the chart-interpretation example, which better distinguishes `asImage` from the Signature method (which also deals with visual content in bounded regions).

**"show it to an end-user to review" → "show it to human to interpret"** — "end-user" and "review" imply a UI display context. "Human to interpret" is broader and makes the use case more legible: the point is that automated extraction failed and a human judgment is required.

**Scanned-doc limitation added to `includeImages`** — either always true and previously undocumented, or noticed while reviewing `includeImages` in the context of the broader image processing topic.

**`query-group.md` table reformat** — triggered by opening the file to add the `[Image processing]` cross-ref; the very wide column widths were inconsistent with other tables and were normalized while editing.
42 changes: 42 additions & 0 deletions .claude/sessions/2026-07-02-region-asImage/friction-log.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# Friction log — region: asImage + percentOverlapX/Y (PR #3351, #3375)

### 1. Loose paraphrasing instead of verbatim copy

**What happened:** When adding `percentOverlapX` and `percentOverlapY` to the region parameter table, Claude rewrote the descriptions rather than copying the existing wording from `intersection.md`, where these same parameters are already documented. Required two interruptions to correct.

**First correction:** "I want you to more precisely copy the wording of the percentOverlap params in intersection for this. don't be loose the way you were just now."

**Second correction (id row):** "I prefer you keep the original wording but add 'by default' like 'where "contained" by default means...' — Configure these thresholds with the Percent Overlap X and Percent Overlap Y parameters."

**Rule:** When wording already exists in another doc for the same parameter (confirmed to share the same underlying implementation), copy it precisely. Only adapt what's structurally required (e.g., dropping an opening clause that's intersection-specific). Do not paraphrase.

---

### 2. Organized session artifact by commit instead of by end state

**What happened:** `frances-edits.md` was initially written commit-by-commit (4 sections, one per commit). User corrected: when commits are iterative stages toward one end goal, the artifact should reflect the final diff, organized by file — not the path taken to get there.

**Rule:** Session edit artifacts should use the consolidated diff between the baseline and the final state. Organize by file, not by commit. Only use commits as the unit of analysis if they represent meaningfully distinct decisions (e.g., different features, separate reviewers). Intermediate commits that are just stages of one authoring session are noise.

---

### 3. Vale style check failed

**What happened:** Vale MCP server (`mcp__vale__check_file`) was not available as a callable tool (not in deferred tool list). Fallback to CLI `vale` also failed:

```
[E100] [loadStyles] Runtime error
style 'Google' does not exist on StylesPath
```

**Result:** Step 5 (style check) was not completed. Files were not checked before committing.

**Root cause:** Vale is not configured correctly in this environment — `StylesPath` does not contain the Google style. Needs investigation.

---

### 3. Artifact location: memory vs. repo

**What happened:** Friction log and checklist were initially written to the memory system (`~/.claude/projects/.../memory/`). User redirected to commit them to the repo instead.

**Rule:** Session artifacts (friction, checklists, open questions) belong in the repo under `.claude/sessions/<date-topic>/`, not in the memory system. Memory is for cross-project, persistent preferences and user context.
46 changes: 46 additions & 0 deletions .claude/skills/update-docs-from-pr/description.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# update-docs-from-pr — How it works

This skill takes a pull request number from the `sensible-hq/sensible` engine repo and produces a docs PR in `sensible-docs`. It runs six steps.

---

## Step 1 — Fetch the PR (deterministic)

Runs two fixed `gh` commands in parallel to get the PR's metadata and full diff, then scans the PR body for references to related PRs and fetches those too. This is mechanical: the commands either succeed or fail, and the output is fixed given a PR number.

## Step 2 — Identify affected docs (non-deterministic)

Claude reads the diff and infers which doc files need updating — by searching for existing mentions of changed features/parameters and mapping the code changes to the doc taxonomy (preprocessors, methods, field types, API, etc.). This is a judgment call. The same PR could reasonably lead to different conclusions about which pages need attention. Hints passed as arguments steer this step.

## Step 3 — Plan the changes (non-deterministic)

Claude loads the style guide (overview, template, sentence guidance, editorial preferences) and decides for each affected area whether to create a new page, update an existing page, or both. Writing or editing content to accurately reflect the engine change — including choosing what to say, what to emphasize, and what examples to include — is inherently generative and non-deterministic.

## Step 4 — Create a branch and make the changes (mixed)

Branch creation is deterministic (`git checkout -b fe_<slug>_docs`). The actual file edits are non-deterministic: Claude writes or rewrites doc content, follows the style guide, and decides how to structure new parameters and examples.

## Step 5 — Style check (mostly deterministic)

Vale is run on every modified file via the MCP server. Errors and warnings are fixed; this is largely rule-driven and deterministic. Applying suggestions (the "maybe fix" tier) requires judgment — Claude decides whether a suggestion fits existing conventions — so that part is non-deterministic.

## Step 6 — Commit and open a PR (deterministic)

Stages only the changed files, commits with a fixed message format referencing the source PR, pushes the branch, and opens a docs PR with a structured body. All of this is mechanical.

---

## Summary

| Step | Nature |
|------|--------|
| 1. Fetch PR + related PRs | Deterministic |
| 2. Identify affected docs | Non-deterministic |
| 3. Plan and write content | Non-deterministic |
| 4. Branch creation | Deterministic |
| 4. File edits | Non-deterministic |
| 5. Vale errors/warnings | Deterministic |
| 5. Vale suggestions | Non-deterministic |
| 6. Commit, push, open PR | Deterministic |

The riskiest non-deterministic steps are 2 and 3 — if Claude misidentifies which docs need updating, or misreads what the engine change means, everything downstream will be wrong. Review the PR diff yourself if the change is subtle.
5 changes: 5 additions & 0 deletions .github/styles/config/vocabularies/Sensible/accept.txt
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,11 @@ Sensible's
[Aa]nyco

# SenseML parameter names (appear in table Name columns)
asImage
percentOverlapX
percentOverlapY
includeImages
isAbsoluteOffset
[Mm]ultimodal
[Mm]ultimodalEngine
[Mm]ulticolumn
Expand Down
35 changes: 35 additions & 0 deletions docs/Senseml reference/concepts/images.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@


```
title: Image processing
excerpt: ''
deprecated: false
hidden: false
metadata:
title: ''
description: 'Extract images and image data from documents'
robots: index
next:
description: ''
```

You have the following options for processing non-text images in documents:

| Use case | Method |
| ------------------------------------------------------------ | ------------------------------------------------------------ |
| Use an LLM to extract structured data from an image. For example, extract facts about a photo of a building, such as its color and whether it's multistory-story or single-story. | use the [Query Group](doc:query-group) method with the Multimodal Engine parameter configured |
| Extract an image from a known region as an encoded string. For example, use this option when your documents contain complex charts, from which neither LLM-based nor layout-based methods can reliably extract structured data. Extract the chart as an image and render it for a human to interpret. | use the [Region](doc:region) method with the As Image parameter configured |
| Search for non-labeled, non-text images in a range. For example, search for unlabeled photos of houses in a real estate document, and extract the images' coordinates. This option returns images' coordinates, which you can then use to render the images yourself. | use the [Document Range](doc:document-range) method with the Include Images parameter configured |

## Notes

- Sensible's rectangular coordinates for images follow these conventions:

* they're in reference to a 0.0 origin at the *top left* corner of the page (not the bottom left origin, as is for example the convention with the popular PDF.js library)

* they're in inches (to convert inches to pixels, multiply the inches coordinates by your PPI setting. For example, an x-coordinate of 3.156 inches is \~227 pixels for a PPI setting of 72 (72 PPI \* 3.156 inches)).

* they're ordered clockwise from top left: (top left), (top right), (bottom right), (bottom left)

- This topic is about processing non-text images. For information about processing text images, see [OCR](doc:ocr).

Loading
Loading