davinci-resolve-mcp 2.222.0 → 2.223.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,50 @@
2
2
 
3
3
  Release history for the DaVinci Resolve MCP Server. The latest release is summarized in the root README; older entries live here to keep the README focused.
4
4
 
5
+ ## What's New in v2.223.0 — native Resolve 21.1 DCTL validation
6
+
7
+ Contributed by @legionsound (#215), live-validated on Studio 21.1.0.14.
8
+
9
+ ### Added
10
+
11
+ - **`dctl validate_native`**, with the granular twin `validate_dctl_native`,
12
+ calling Resolve 21.1's own `ValidateDCTL`. The existing `dctl validate`
13
+ remains the static offline checker — this is new surface beside it, not a
14
+ change to what that action claims. Tool count 375 → 376.
15
+ - **Source layout is passed through unchanged and native diagnostics are
16
+ returned verbatim.** That is the rule recorded in the ledger back in
17
+ v2.216.1, when @legionsound narrowed `ValidateDCTL` to being sensitive to
18
+ source layout — the same function validates multi-line and fails on one line
19
+ — and it is now implemented rather than merely written down: a wrapper that
20
+ reflowed the user's source to make validation pass would be hiding the very
21
+ behaviour the ledger entry exists to warn about.
22
+ - `None` means valid, strings mean invalid, and an **unexpected native result
23
+ type is an error rather than a false success** — the distinction that keeps a
24
+ changed API from silently reading as "your shader is fine".
25
+ - Version-gated and explicitly classified **read-only**: verified here as LOW /
26
+ non-destructive. It does not install, encrypt, apply or render a DCTL, and
27
+ a successful validation is not a rendered shader test.
28
+
29
+ ### Validation
30
+
31
+ - Full suite green: 3,470 passed, 1 skipped. Focused contracts cover CRLF and
32
+ Unicode preservation, so the source that reaches Resolve is byte-for-byte
33
+ what the caller supplied.
34
+ - Live evidence is @legionsound's on Studio 21.1.0.14, checked against the
35
+ official Resolve MCP and both community interfaces: the multi-line identity
36
+ fixture validates, its one-line form reproduces the known missing-return
37
+ diagnostic, and invalid source returns the missing-entry-function
38
+ diagnostic — with both wrappers matching native results exactly. Not
39
+ reproduced here; this machine is Studio 19.1.3.7, below the 21.1 floor.
40
+ - **Not claimed**: encryption, and any statement that validation implies a
41
+ shader renders correctly.
42
+
43
+ ### Changed
44
+
45
+ - Adapted on merge, as with #212, #213 and #214: counts resolved to **376**,
46
+ confirmed by the agent-rule generator, generated files regenerated rather
47
+ than hand-merged. No behaviour changed in the adaptation.
48
+
5
49
  ## What's New in v2.222.0 — native Resolve 21.1 timecode and waveform alignment
6
50
 
7
51
  Contributed by @legionsound (#212), live-validated on Studio 21.1.0.14.
package/README.md CHANGED
@@ -2,10 +2,10 @@
2
2
 
3
3
  English | [简体中文](README.zh-CN.md)
4
4
 
5
- [![Version](https://img.shields.io/badge/version-2.222.0-blue.svg)](https://github.com/samuelgursky/davinci-resolve-mcp/releases)
5
+ [![Version](https://img.shields.io/badge/version-2.223.0-blue.svg)](https://github.com/samuelgursky/davinci-resolve-mcp/releases)
6
6
  [![npm](https://img.shields.io/npm/v/davinci-resolve-mcp.svg?label=npm&color=CB3837)](https://www.npmjs.com/package/davinci-resolve-mcp)
7
7
  [![API Coverage](https://img.shields.io/badge/API%20Coverage-100%25-brightgreen.svg)](docs/reference/api-coverage.md)
8
- [![Tools](https://img.shields.io/badge/MCP%20Tools-36%20(375%20full)-blue.svg)](#server-modes)
8
+ [![Tools](https://img.shields.io/badge/MCP%20Tools-36%20(376%20full)-blue.svg)](#server-modes)
9
9
  [![Advanced](https://img.shields.io/badge/Advanced%20(offline)-18%20tools-blueviolet.svg)](#server-modes)
10
10
  [![Tested](https://img.shields.io/badge/Live%20Tested-93.6%25-green.svg)](docs/reference/api-coverage.md#test-results)
11
11
  [![DaVinci Resolve](https://img.shields.io/badge/DaVinci%20Resolve-18.5+-darkred.svg)](https://www.blackmagicdesign.com/products/davinciresolve)
@@ -133,7 +133,7 @@ The command starts a loopback-only server and opens the control panel in your br
133
133
  | Mode | Entry point | Tools | Best for |
134
134
  |------|-------------|-------|----------|
135
135
  | Compound | `src/server.py` | 36 | Default mode for most assistants. Related Resolve operations are grouped behind action parameters to keep context usage low. |
136
- | Full / granular | `src/server.py --full` or `src/resolve_mcp_server.py` | 375 | Power users who want one MCP tool per Resolve API method. |
136
+ | Full / granular | `src/server.py --full` or `src/resolve_mcp_server.py` | 376 | Power users who want one MCP tool per Resolve API method. |
137
137
 
138
138
  The compound server is recommended unless you specifically need the granular one-tool-per-method surface.
139
139
 
@@ -365,7 +365,7 @@ The default server is a local stdio process launched by your MCP client; it does
365
365
 
366
366
  | Metric | Value |
367
367
  |--------|-------|
368
- | MCP Tools | **36** compound / **375** granular (live server) |
368
+ | MCP Tools | **36** compound / **376** granular (live server) |
369
369
  | Advanced (offline) tools | **18** — .drp/.drt/.drx + DB authoring, no Resolve running |
370
370
  | Kernel Actions | **136** guarded workflow actions across 9 compound tools |
371
371
  | API Methods Covered | **361/361** (100%) |
package/README.zh-CN.md CHANGED
@@ -2,17 +2,17 @@
2
2
 
3
3
  [English](README.md) | 简体中文
4
4
 
5
- [![Version](https://img.shields.io/badge/version-2.222.0-blue.svg)](https://github.com/samuelgursky/davinci-resolve-mcp/releases)
5
+ [![Version](https://img.shields.io/badge/version-2.223.0-blue.svg)](https://github.com/samuelgursky/davinci-resolve-mcp/releases)
6
6
  [![npm](https://img.shields.io/npm/v/davinci-resolve-mcp.svg?label=npm&color=CB3837)](https://www.npmjs.com/package/davinci-resolve-mcp)
7
7
  [![API Coverage](https://img.shields.io/badge/API%20Coverage-100%25-brightgreen.svg)](docs/reference/api-coverage.md)
8
- [![Tools](https://img.shields.io/badge/MCP%20Tools-36%20(375%20full)-blue.svg)](#服务器模式)
8
+ [![Tools](https://img.shields.io/badge/MCP%20Tools-36%20(376%20full)-blue.svg)](#服务器模式)
9
9
  [![Advanced](https://img.shields.io/badge/Advanced%20(offline)-18%20tools-blueviolet.svg)](#服务器模式)
10
10
  [![Tested](https://img.shields.io/badge/Live%20Tested-93.6%25-green.svg)](docs/reference/api-coverage.md#test-results)
11
11
  [![DaVinci Resolve](https://img.shields.io/badge/DaVinci%20Resolve-18.5+-darkred.svg)](https://www.blackmagicdesign.com/products/davinciresolve)
12
12
  [![Python](https://img.shields.io/badge/python-3.10+-green.svg)](https://www.python.org/downloads/)
13
13
  [![License](https://img.shields.io/badge/license-MIT-blue.svg)](https://opensource.org/licenses/MIT)
14
14
 
15
- > 本翻译对应 v2.222.0 版 README。如与英文原版有出入,以 [英文原版](README.md) 为准。
15
+ > 本翻译对应 v2.223.0 版 README。如与英文原版有出入,以 [英文原版](README.md) 为准。
16
16
 
17
17
  一个 Model Context Protocol (MCP) 服务器,让 AI 助手通过官方脚本 API 控制 DaVinci Resolve Studio(达芬奇)。它提供完整的 API 覆盖,外加带护栏的工作流助手,涵盖剪辑、媒体池整理、渲染设置、审阅标记、调色、Fusion、Fairlight、项目生命周期任务、扩展开发,以及不碰源媒体的媒体分析。
18
18
 
@@ -88,7 +88,7 @@ venv/bin/python -m src.control_panel
88
88
  | 模式 | 入口 | 工具数 | 适合谁 |
89
89
  |------|------|--------|--------|
90
90
  | Compound(复合) | `src/server.py` | 36 | 大多数助手的默认模式。相关的 Resolve 操作按 action 参数分组,压低上下文占用。 |
91
- | Full / granular(细粒度) | `src/server.py --full` 或 `src/resolve_mcp_server.py` | 375 | 想要"一个 Resolve API 方法 = 一个 MCP 工具"的重度用户。 |
91
+ | Full / granular(细粒度) | `src/server.py --full` 或 `src/resolve_mcp_server.py` | 376 | 想要"一个 Resolve API 方法 = 一个 MCP 工具"的重度用户。 |
92
92
 
93
93
  除非你明确需要一方法一工具的细粒度界面,否则推荐复合模式。
94
94
 
@@ -226,7 +226,7 @@ DRX 调色写入**针对 Resolve Studio 做过实机校准**:调色参数默
226
226
 
227
227
  | 指标 | 数值 |
228
228
  |------|------|
229
- | MCP 工具 | **36** 复合 / **375** 细粒度(实时服务器) |
229
+ | MCP 工具 | **36** 复合 / **376** 细粒度(实时服务器) |
230
230
  | Advanced(离线)工具 | **18**——.drp/.drt/.drx + 数据库创作,无需 Resolve 运行 |
231
231
  | 内核 action | 9 个复合工具下 **136** 个带护栏的工作流 action |
232
232
  | API 方法覆盖 | **361/361**(100%) |
package/docs/SKILL.md CHANGED
@@ -345,7 +345,7 @@ to the user as verified.
345
345
  | Mode | Entry point | Tool count | Use when |
346
346
  |---|---|---|---|
347
347
  | Compound (default) | `src/server.py` | 36 tools | Most workflows — keeps context lean |
348
- | Granular (full) | `src/server.py --full` | 375 tools | Power users needing one tool per API method |
348
+ | Granular (full) | `src/server.py --full` | 376 tools | Power users needing one tool per API method |
349
349
 
350
350
  Resolve 21.1 adds [twelve read-only discovery controls](reference/resolve211-read-controls.md)
351
351
  for edition, presets, audio formats/codecs, normalization modes, speed, fades
@@ -2490,3 +2490,5 @@ Native timeline/clip output blanking: [21.1 controls](reference/resolve211-blank
2490
2490
  Native audio normalization: [21.1 controls](reference/resolve211-normalization.md), with independently measured exported-audio evidence.
2491
2491
 
2492
2492
  Native timecode/waveform alignment: [21.1 controls](reference/resolve211-alignment.md), including linked-item selection semantics and rendered video/audio evidence.
2493
+
2494
+ Resolve-native DCTL validation: [21.1 controls](reference/resolve211-dctl-validation.md), separate from static validation and shader rendering.
@@ -64,7 +64,7 @@ davinci-resolve-mcp/
64
64
  ├── install.py # Universal installer (macOS/Windows/Linux)
65
65
  ├── src/
66
66
  │ ├── server.py # Compound MCP server — 36 tools (default)
67
- │ ├── resolve_mcp_server.py # Thin full-server entrypoint — 375 tools
67
+ │ ├── resolve_mcp_server.py # Thin full-server entrypoint — 376 tools
68
68
  │ ├── granular/ # Modular full-server implementation
69
69
  │ └── utils/ # Platform detection, Resolve connection helpers
70
70
  ├── tests/ # offline suite (test_*.py) + live harnesses (live_*.py):
package/docs/install.md CHANGED
@@ -144,7 +144,7 @@ The MCP server comes in two modes:
144
144
  | Mode | File | Tools | Best For |
145
145
  |------|------|-------|----------|
146
146
  | **Compound** (default) | `src/server.py` | 36 | Most users — fast, clean, low context usage |
147
- | **Full** | `src/resolve_mcp_server.py` | 375 | Power users who want one tool per API method |
147
+ | **Full** | `src/resolve_mcp_server.py` | 376 | Power users who want one tool per API method |
148
148
 
149
149
  The compound server's `timeline_item` tool includes dedicated actions for common workflows:
150
150
 
@@ -159,7 +159,7 @@ The compound server's `timeline_item` tool includes dedicated actions for common
159
159
 
160
160
  The installer uses the compound server by default. To use the full server:
161
161
  ```bash
162
- python src/server.py --full # Launch full 375-tool server
162
+ python src/server.py --full # Launch full 376-tool server
163
163
  # Or point your MCP config directly at src/resolve_mcp_server.py
164
164
  ```
165
165
 
@@ -25,7 +25,7 @@ Every non-deprecated method in the bundled legacy README is represented. This
25
25
  does not claim complete coverage of the newer Resolve 21.1 typed API. The
26
26
  default compound server exposes **36 tools** that group related operations by
27
27
  action parameter, keeping LLM context windows lean. The full granular server
28
- provides **375 individual tools** for power users. The legacy coverage spans
28
+ provides **376 individual tools** for power users. The legacy coverage spans
29
29
  13 API object classes. MCP-level kernel actions are tracked separately in
30
30
  [Kernel Action Coverage](../kernels/README.md).
31
31
 
@@ -640,3 +640,5 @@ Native timeline/clip output blanking: [21.1 controls](resolve211-blanking.md), w
640
640
  Native audio normalization: [21.1 controls](resolve211-normalization.md), with independently measured exported-audio evidence.
641
641
 
642
642
  Native timecode/waveform alignment: [21.1 controls](resolve211-alignment.md), including linked-item selection semantics and rendered video/audio evidence.
643
+
644
+ Resolve-native DCTL validation: [21.1 controls](resolve211-dctl-validation.md), separate from static validation and shader rendering.
@@ -766,5 +766,5 @@ values, or automation-hostile modal prompts.
766
766
  - **Object:** `Resolve`
767
767
  - **Signature:** `(dctlSource) -> str | None (21.1+)`
768
768
  - **Behavior:** Reported by @legionsound (issue #207) from Studio 21.1.0.14 on macOS; NOT reproduced here (no 21.1 install). The documented success result is None. A minimal identity transform written across several lines — `__DEVICE__ float3 transform(...)` with the body on its own lines — validates (None). The SAME function collapsed onto one line consistently returns 'DCTL Error: main DCTL function does not have return value.', which is false: the return statement is there. A genuinely invalid source returns 'cannot find main DCTL function.', so the validator does distinguish; it is the single-line layout it misreads. An earlier multi-line timeout did not reproduce after a Resolve restart with a 30-second limit. Nothing establishes a GPU compiler or render defect — this is the validator's parse, not the DCTL's execution. EncryptDCTL untested.
769
- - **Workaround / current handling:** Any wrapper around ValidateDCTL must pass the native diagnostic through verbatim and must not reflow or rewrite the user's source to dodge it; ship the multi-line identity fixture as the known-good control. A 'no return value' error on a one-line function is this quirk, not a missing return — re-run the validation with the function laid out across lines before believing it. This server's own `dctl validate` is a static, offline check (entry point, brace balance, float suffixes) and does not call ValidateDCTL at all.
769
+ - **Workaround / current handling:** Any wrapper around ValidateDCTL must pass the native diagnostic through verbatim and must not reflow or rewrite the user's source to dodge it; ship the multi-line identity fixture as the known-good control. A 'no return value' error on a one-line function is this quirk, not a missing return — re-run the validation with the function laid out across lines before believing it. This server's own `dctl validate` is a static, offline check (entry point, brace balance, float suffixes) and does not call ValidateDCTL at all. The separate `dctl validate_native` and granular `validate_dctl_native` now expose the native validator without changing source or diagnostics. Both interfaces were contributor-validated against the three fixtures on Studio 21.1.0.14; see resolve211-dctl-validation.md.
770
770
  - **Tags:** dctl, validation, unreliable-return, version-gated, reported
@@ -0,0 +1,31 @@
1
+ # Native DCTL validation in Resolve 21.1
2
+
3
+ Compound `dctl validate_native` and granular `validate_dctl_native` accept a
4
+ `source` string and call Resolve.ValidateDCTL. They return `valid`, `diagnostic`
5
+ and `checker: resolve_native`. The source is passed unchanged, including its
6
+ line layout. Native None means valid; a native string means invalid and is
7
+ returned verbatim, including whitespace. An unexpected native result type is a
8
+ protocol error, not a claim that the shader validated.
9
+
10
+ The existing `dctl validate` remains the static offline checker. Native validation
11
+ requires running Resolve 21.1 and a callable ValidateDCTL method. It does not
12
+ install a DCTL, encrypt it, apply a grade or render the shader. A successful
13
+ validation is not rendered-output evidence. The granular tool is read-only and
14
+ the compound action is explicitly classified as non-destructive.
15
+
16
+ ## Contributor validation
17
+
18
+ Contributor-validated on macOS Studio 21.1.0.14 against the official MCP and both
19
+ actual community interfaces. The multiline identity fixture returns None. The
20
+ same function on one line returns `DCTL Error: main DCTL function does not have
21
+ return value.` Invalid source returns `cannot find main DCTL function.` Both
22
+ wrappers preserve these diagnostics exactly. The source-layout limitation is
23
+ already in api_truth; this wrapper exposes it honestly rather than reformatting
24
+ user code to hide it.
25
+
26
+ `python tests/live_resolve211_dctl.py` compares raw/native and both wrapper
27
+ results for all three fixtures. It neither changes projects nor installs files.
28
+ Unit tests also cover verbatim CRLF/Unicode source and diagnostic handling,
29
+ invalid inputs, missing methods, unexpected native result types, read-only risk
30
+ classification and preservation of the static checker route. Encryption and
31
+ actual GPU execution remain separate work.
package/install.py CHANGED
@@ -37,7 +37,7 @@ from src.utils.update_check import (
37
37
 
38
38
  # ─── Version ──────────────────────────────────────────────────────────────────
39
39
 
40
- VERSION = "2.222.0"
40
+ VERSION = "2.223.0"
41
41
  # Only hard floor: mcp[cli] requires Python 3.10+. There is no upper bound —
42
42
  # Resolve's scripting bridge loads into newer interpreters on recent builds
43
43
  # (Python 3.14 verified against Resolve Studio 20.3.2). Older Resolve builds
@@ -1543,7 +1543,7 @@ def verify_resolve_connection(python_path, api_path, lib_path):
1543
1543
 
1544
1544
  def print_banner():
1545
1545
  title = f"DaVinci Resolve MCP Server — Installer v{VERSION}"
1546
- subtitle = "36 compound · 375 full · 3 platforms"
1546
+ subtitle = "36 compound · 376 full · 3 platforms"
1547
1547
  print()
1548
1548
  print(bold(" ╔══════════════════════════════════════════════════════╗"))
1549
1549
  print(bold(f" ║{title:^54}║"))
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "davinci-resolve-mcp",
3
- "version": "2.222.0",
3
+ "version": "2.223.0",
4
4
  "description": "NPM bootstrapper for the DaVinci Resolve MCP Server.",
5
5
  "license": "MIT",
6
6
  "author": "Samuel Gursky <samgursky@gmail.com>",
@@ -87,7 +87,7 @@ if not logging.getLogger().handlers:
87
87
  handlers=[logging.StreamHandler()],
88
88
  )
89
89
 
90
- VERSION = "2.222.0"
90
+ VERSION = "2.223.0"
91
91
  logger = logging.getLogger("davinci-resolve-mcp")
92
92
  logger.info(f"Starting DaVinci Resolve MCP Server v{VERSION}")
93
93
  logger.info(f"Detected platform: {get_platform()}")
@@ -1,4 +1,5 @@
1
1
  """Native Resolve 21.1 discovery and editing controls."""
2
+ from src.utils.resolve211_dctl import native_dctl_result
2
3
  from src.utils.resolve211_alignment import auto_align
3
4
  from src.utils.resolve211_normalization import normalize_audio
4
5
  from src.utils.resolve211_blanking import validate_blanking
@@ -304,3 +305,17 @@ def auto_align_timeline_clips(item_ids: list[str], options: dict | None = None)
304
305
  if missing:
305
306
  return missing
306
307
  return auto_align(get_resolve(), timeline, item_ids, {} if options is None else options)
308
+
309
+
310
+ @mcp.tool(annotations=READ_ONLY_TOOL)
311
+ def validate_dctl_native(source: str) -> dict:
312
+ """Validate shader source with Resolve 21.1. Source layout and native diagnostics are preserved; success means validation, not a rendered shader test."""
313
+ if not isinstance(source, str):
314
+ return {"error": "source must be a string"}
315
+ r = get_resolve()
316
+ if r is None:
317
+ return {"error": "Not connected to DaVinci Resolve"}
318
+ missing = _requires_method(r, "ValidateDCTL", "21.1")
319
+ if missing:
320
+ return missing
321
+ return native_dctl_result(r, source)
@@ -34,7 +34,7 @@ from src.utils.update_check import start_background_update_check
34
34
  if __name__ == "__main__":
35
35
  try:
36
36
  start_background_update_check(VERSION, project_dir, logger)
37
- logger.info(f"Starting DaVinci Resolve MCP Server v{VERSION} (375 granular tools)")
37
+ logger.info(f"Starting DaVinci Resolve MCP Server v{VERSION} (376 granular tools)")
38
38
  run_fastmcp_stdio(mcp)
39
39
  except KeyboardInterrupt:
40
40
  logger.info("Server shutdown requested")
package/src/server.py CHANGED
@@ -8,10 +8,10 @@ Each tool groups related operations via an 'action' parameter.
8
8
 
9
9
  Usage:
10
10
  python src/server.py # Start the MCP server
11
- python src/server.py --full # Start the 375-tool granular server instead
11
+ python src/server.py --full # Start the 376-tool granular server instead
12
12
  """
13
13
 
14
- VERSION = "2.222.0"
14
+ VERSION = "2.223.0"
15
15
 
16
16
  import base64
17
17
  import os
@@ -45,6 +45,7 @@ for p in [current_dir, project_dir]:
45
45
  from src.utils.resolve211_multicam import create_multicam, resolve_constant, GRADES
46
46
  from src.utils.resolve211_blanking import validate_blanking
47
47
  from src.utils.resolve211_alignment import auto_align
48
+ from src.utils.resolve211_dctl import native_dctl_result
48
49
  from src.utils.resolve211_normalization import normalize_audio
49
50
  from src.utils.resolve211_edits import validate_edit_options, validate_transition_options, transition_result
50
51
 
@@ -31142,6 +31143,7 @@ def dctl(action: str, params: Optional[Dict[str, Any]] = None) -> Dict[str, Any]
31142
31143
  remove(name, category?, subdir?, ext?) -> {success}
31143
31144
  read(name, category?, subdir?, ext?) -> {source, encrypted}
31144
31145
  validate(source) -> {valid, errors, warnings, checker}
31146
+ validate_native(source) -> {valid, diagnostic, checker} — Resolve 21.1 validation; source and diagnostic unchanged.
31145
31147
  template(kind, name, options?) -> {source, kind, name, suggested_category}
31146
31148
  — kind: 'transform' | 'transform_alpha' | 'transition' | 'matrix' |
31147
31149
  'kernel' | 'lut_apply' | 'aces_idt' | 'aces_odt'
@@ -31295,6 +31297,18 @@ def dctl(action: str, params: Optional[Dict[str, Any]] = None) -> Dict[str, Any]
31295
31297
  return {"source": src, "path": target,
31296
31298
  "encrypted": ext == ".dctle", "category": cat}
31297
31299
 
31300
+ if action == "validate_native":
31301
+ source = p.get("source")
31302
+ if not isinstance(source, str):
31303
+ return _err("validate_native requires a source string")
31304
+ r = get_resolve()
31305
+ if r is None:
31306
+ return _not_connected_error()
31307
+ missing = _requires_method(r, "ValidateDCTL", "21.1")
31308
+ if missing:
31309
+ return missing
31310
+ return native_dctl_result(r, source)
31311
+
31298
31312
  if action == "validate":
31299
31313
  source = p.get("source")
31300
31314
  if not isinstance(source, str):
@@ -31321,7 +31335,7 @@ def dctl(action: str, params: Optional[Dict[str, Any]] = None) -> Dict[str, Any]
31321
31335
  }
31322
31336
 
31323
31337
  return _unknown(action, ["path", "list", "install", "remove", "read",
31324
- "validate", "template", "list_templates"])
31338
+ "validate_native", "validate", "template", "list_templates"])
31325
31339
 
31326
31340
 
31327
31341
  # ═══════════════════════════════════════════════════════════════════════════════
@@ -32737,9 +32751,9 @@ if __name__ == "__main__":
32737
32751
  start_background_update_check(VERSION, project_dir, logger, env=_setup_update_env())
32738
32752
  _install_threaded_tool_dispatch(mcp)
32739
32753
 
32740
- # Support --full flag to run the 375-tool granular server instead
32754
+ # Support --full flag to run the 376-tool granular server instead
32741
32755
  if "--full" in sys.argv:
32742
- logger.info("Starting full 375-tool granular server...")
32756
+ logger.info("Starting full 376-tool granular server...")
32743
32757
  sys.argv = [arg for arg in sys.argv if arg != "--full"]
32744
32758
  from src.granular import mcp as granular_mcp
32745
32759
 
@@ -3263,7 +3263,12 @@ API_TRUTH: List[Dict[str, Any]] = [
3263
3263
  "across lines before believing it. This server's own "
3264
3264
  "`dctl validate` is a static, offline check (entry point, "
3265
3265
  "brace balance, float suffixes) and does not call "
3266
- "ValidateDCTL at all.",
3266
+ "ValidateDCTL at all. The separate `dctl validate_native` and "
3267
+ "granular `validate_dctl_native` now expose the native "
3268
+ "validator without changing source or diagnostics. Both "
3269
+ "interfaces were contributor-validated against the three "
3270
+ "fixtures on Studio 21.1.0.14; see "
3271
+ "resolve211-dctl-validation.md.",
3267
3272
  "tags": ["dctl", "validation", "unreliable-return", "version-gated", "reported"],
3268
3273
  "submit": "bug",
3269
3274
  },
@@ -404,7 +404,7 @@ class RiskClassificationHook(LifecycleHook):
404
404
  else BlastRadius.ITEM
405
405
  )
406
406
  reasons.append(f"Recoverable edit to existing state: {action}")
407
- elif any(action.startswith(p) for p in cls._READ_ONLY_PREFIXES) or action in {"read", "status", "info"}:
407
+ elif any(action.startswith(p) for p in cls._READ_ONLY_PREFIXES) or action in {"read", "status", "info"} or pair == ("dctl", "validate_native"):
408
408
  level = RiskLevel.LOW
409
409
  destructive = False
410
410
  radius = BlastRadius.ITEM
@@ -0,0 +1,8 @@
1
+ """Native DCTL diagnostics are evidence; never reformat the user's shader source."""
2
+
3
+
4
+ def native_dctl_result(resolve, source):
5
+ diagnostic=resolve.ValidateDCTL(source)
6
+ if diagnostic is not None and not isinstance(diagnostic,str):
7
+ return {'error':'ValidateDCTL returned an unexpected diagnostic type'}
8
+ return {'valid':diagnostic is None,'diagnostic':diagnostic,'checker':'resolve_native'}
@@ -226,6 +226,7 @@ _EVIDENCE_GATES: List[Dict[str, Any]] = [
226
226
 
227
227
  CODE_FLOORS: Dict[str, str] = {
228
228
  "Timeline.AutoAlignClips": "21.1",
229
+ "Resolve.ValidateDCTL": "21.1",
229
230
  "MediaPool.CreateMulticamClip": "21.1",
230
231
  "TimelineItem.FlattenMulticam": "21.1",
231
232
  "Timeline.SetOutputBlanking": "21.1",