You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Follow-up to the v1.5.0 cleanup. A four-angle audit found a handful of stale references and one coverage gap; this commit closes them all.
Doc fixes (live docs that lied about current state):
- CONTRIBUTING.md vocabulary schema: optional fields list said `mask_kind`/`mask_ref`; updated to `mask_spec` with the drawn-form shape, noting the v1.5.0 retirement.
- vocabulary/starter/README.md: dropped the deleted `tone_lifted_shadows_subject` row, fixed the count (5 → 4), explained why mask-bound starter entries are out for now.
- docs/adr/TA.md MCP component: corrected stale "27 tools across ... masks ... plus context stubs" to current 22 (vocab/edit 5 + versioning 6 + rendering 3 + ingest 3 + context 5).
- docs/testing.md: bumped "27 shipped tools" → 22, replaced `tone_lifted_shadows_subject` example with `gradient_top_dampen_highlights`, dropped the dead Masks tool category, rewrote the mask-bound coverage line around `apply_with_drawn_mask` and the spatial-difference assertion.
- docs/concept/02-project-concept.md § 10.1: rewrote the "configure a masking provider beyond the bundled coarse default" line; there is no bundled default. Phase 4 framed as drawn-form geometry, not PNG providers.
- docs/IMPLEMENTATION.md Slice 4: prepended a "Status note (2026-05-03) — superseded by ADR-076" callout. Historical narrative preserved as build record.
Append-only ADRs (partial-supersession status markers, mirroring what we did for ADR-021/022/055/057/058/074):
- ADR-056 (MCP tool surface): noted the 5 mask tools and `mask_override` arg are gone; surface is 22 not 27. Error-contract rules still in force.
- ADR-070 (CLI framework: Typer): noted the `masks` sub-command group is gone; CLI now has 1 sub-app (vocab) not 2. Typer choice stands.
Coverage gap (test integrity):
- tests/unit/mcp/tools/test_vocab_edit.py: added test_apply_primitive_with_mask_spec_routes_through_drawn_mask (proves the mask_spec branch in vocab_edit.py:_apply_primitive injects darktable:masks_history into the snapshotted XMP) and test_apply_primitive_with_invalid_mask_spec_returns_masking_error (malformed spec → MASKING_ERROR, not a stack trace).
- tests/integration/cli/test_cli_edit.py: added test_apply_primitive_with_mask_spec_routes_through_drawn_mask using `--pack expressive-baseline` and `gradient_top_dampen_highlights`. Mirrors the MCP coverage at the CLI dispatch layer.
Both branches now have explicit unit/integration coverage that doesn't require real darktable. The e2e tests in tests/e2e/expressive/test_mask_bound_entries.py continue to prove the binding actually shapes pixels.
CI: 440 unit + 206 integration + all gates green.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copy file name to clipboardExpand all lines: docs/CONTRIBUTING.md
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -240,7 +240,7 @@ Some sliders have minimum granularity that prevents authoring exact zero values.
240
240
241
241
Starting v0.3.0, vocabulary packs are loaded by `chemigram.core.vocab.VocabularyIndex` against a per-pack `manifest.json`. A pack is a directory whose root contains `manifest.json` plus a tree of `.dtstyle` files (the layout under `vocabulary/starter/` follows `layers/L1`, `layers/L2`, `layers/L3` per the architecture doc).
242
242
243
-
The manifest's top-level shape is `{"entries": [...]}`. Each entry object follows the contract in `docs/adr/TA.md``contracts/vocabulary-manifest`. Required fields per entry: `name`, `layer`, `path`, `touches`, `tags`, `description`, `modversions`, `darktable_version`, `source`, `license`. Optional: `subtype`, `mask_kind`, `mask_ref`, `global_variant`, `applies_to`. L1 entries must include `applies_to: {make, model, lens_model}` (exact-match per ADR-053).
243
+
The manifest's top-level shape is `{"entries": [...]}`. Each entry object follows the contract in `docs/adr/TA.md``contracts/vocabulary-manifest`. Required fields per entry: `name`, `layer`, `path`, `touches`, `tags`, `description`, `modversions`, `darktable_version`, `source`, `license`. Optional: `subtype`, `mask_spec`, `global_variant`, `applies_to`. L1 entries must include `applies_to: {make, model, lens_model}` (exact-match per ADR-053). Mask-bound entries declare a `mask_spec` of shape `{"dt_form": "gradient" | "ellipse" | "rectangle", "dt_params": {...}}` per ADR-076; the v1.4-and-earlier `mask_kind` / `mask_ref` fields were retired in v1.5.0 along with the PNG-mask path.
244
244
245
245
The index validates eagerly: the dtstyle file must exist relative to `pack_root`, must parse cleanly, and the user-authored plugin's `<operation>` must appear in the manifest entry's `touches` list. Mismatches are `ManifestError` with the offending entry name in the message — fix the manifest, not the parser.
> **Status note (2026-05-03):** the substance of this slice — the `MaskingProvider` Protocol, `CoarseAgentProvider`, the PNG mask registry, the five mask MCP tools, the `mask_kind`/`mask_ref` schema, the `mask_override` apply argument — was all retired in v1.5.0 (ADR-076) when we discovered darktable doesn't read external PNG raster masks. The drawn-mask path (path 4a, v1.4.0) replaced it, validated end-to-end against real darktable. The historical scope below is preserved as build-record; for current architecture see ADR-076 and `concept/04-architecture.md` § 6.
> Status · Accepted; partially superseded by ADR-076 (2026-05-03) — the 5 mask tools (`generate_mask`, `regenerate_mask`, `list_masks`, `tag_mask`, `invalidate_mask`) and the `apply_primitive(mask_override=…)` parameter were removed in v1.5.0; the surface is now 22 tools, not 27. The error-contract and parameter-shape rules in this ADR remain in force for the surviving tools.
4
4
> Date · 2026-04-29
5
5
> TA anchor · /components/mcp-server, /contracts/mcp-tools
6
6
> Related RFC · RFC-010 (closes); supersedes the implementation note in ADR-033
Copy file name to clipboardExpand all lines: docs/adr/ADR-070-cli-framework-typer.md
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1,6 +1,6 @@
1
1
# ADR-070 — CLI framework: Typer
2
2
3
-
> Status · Accepted
3
+
> Status · Accepted; partially superseded by ADR-076 (2026-05-03) — the `masks` sub-command group (list/generate/regenerate/tag/invalidate) was removed in v1.5.0; the CLI now has 1 sub-command group (`vocab`), not 2. Typer remains the framework choice and the rest of this ADR's reasoning stands.
Copy file name to clipboardExpand all lines: docs/concept/02-project-concept.md
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -437,7 +437,7 @@ Putting it all together — what a photographer experiences from first install t
437
437
438
438
Install Chemigram. Initial setup creates `~/.chemigram/` with empty `taste.md`, default `config.toml`, isolated darktable configdir. Photographer spends an hour writing initial `taste.md` — what they can articulate about their preferences. Imperfect; fine.
439
439
440
-
Optionally configure a masking provider beyond the bundled coarse default. For production-quality work on subjects, install `chemigram-masker-sam` sibling project.
440
+
Note that v1.5.0 ships drawn-form geometric masks (gradient / ellipse / rectangle) baked into vocabulary entries' `mask_spec`. There is no AI-driven masker today; subject-precise content-aware masking is Phase 4 work via a sibling project (working name `chemigram-masker-sam`) that will produce darktable drawn-form geometry, not PNG bytes. ADR-076 documents the architecture and supersedes the v1.4-and-earlier PNG-mask path.
- Reset / branch / checkout semantics: each followed by a render to confirm the workspace state is intact.
106
-
- Mask-bound primitives: real mask materialization → real render → assert the masked region differs from the unmasked region.
106
+
- Mask-bound primitives: real `apply_with_drawn_mask` synthesis → real render → assert the masked region differs *spatially*from a same-dtstyle uniform render (path 4a; v1.4.0+).
107
107
108
108
**Doesn't belong:**
109
109
- Anything that doesn't ultimately validate pixels or filesystem state from a real darktable invocation.
@@ -119,7 +119,7 @@ These are the rules a PR must satisfy before it lands.
119
119
- One unit test per input-validation path (schema rejects malformed input).
120
120
- One integration test per error code the tool can return (`recoverable=True` errors all need at least one test).
121
121
- One integration test for the happy path through `in_memory_session`.
122
-
- If the tool produces side-effects on the filesystem (snapshot, mask, transcript): one integration test that asserts the post-state.
122
+
- If the tool produces side-effects on the filesystem (snapshot, transcript): one integration test that asserts the post-state.
123
123
- If the tool drives a render: one e2e test that asserts on the rendered pixels.
124
124
125
125
### When you add a vocabulary primitive
@@ -165,11 +165,11 @@ Every shipped primitive needs end-to-end pixel validation. The 5 starter entries
-**Drawn-mask apply:**`apply_primitive` for entries with `mask_spec` set (routes through `apply_with_drawn_mask`; e2e proves the binding shapes the rendered effect). Standalone mask MCP tools were removed in v1.5.0 per ADR-076.
Copy file name to clipboardExpand all lines: vocabulary/starter/README.md
+2-3Lines changed: 2 additions & 3 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1,6 +1,6 @@
1
1
# Starter Vocabulary
2
2
3
-
The vocabulary pack that ships with `pip install chemigram`. **Deliberately small** — five entries, generic by design — so the agent loop works out of the box. Phase 2 grows the vocabulary from real session evidence, not from imagined upfront completeness; the gaps surfaced via `log_vocabulary_gap` are the seed for new entries.
3
+
The vocabulary pack that ships with `pip install chemigram`. **Deliberately small** — four entries, generic by design — so the agent loop works out of the box. Phase 2 grows the vocabulary from real session evidence, not from imagined upfront completeness; the gaps surfaced via `log_vocabulary_gap` are the seed for new entries.
4
4
5
5
See `docs/concept/04-architecture.md` § 5 (layer model) for the L1/L2/L3 architecture, and `docs/prd/PRD-003-vocabulary-as-voice.md` for the design rationale.
6
6
@@ -12,9 +12,8 @@ See `docs/concept/04-architecture.md` § 5 (layer model) for the L1/L2/L3 archit
|`tone_lifted_shadows_subject`| L3 | exposure | raster (subject) | Shadow lift restricted to the subject mask |
16
15
17
-
The mask-bound entry references `current_subject_mask` — the agent generates this via `generate_mask(image_id, target="subject")` before applying.
16
+
Mask-bound starter entries are out for now: the original `tone_lifted_shadows_subject` was retired in v1.5.0 alongside the PNG-mask architecture (ADR-076). Drawn-form mask-bound entries (gradient / ellipse / rectangle) live in the `expressive-baseline` pack; the starter pack stays minimal until evidence motivates a starter-level mask-bound primitive.
0 commit comments