Skip to content

fix(api-tox): Codex P1+P2 followups on auto-rollback (PR #34) - #36

Merged
dreamrec merged 2 commits into
mainfrom
claude/v2.2.0-feature-1.1.1-codex-followup
May 11, 2026
Merged

fix(api-tox): Codex P1+P2 followups on auto-rollback (PR #34)#36
dreamrec merged 2 commits into
mainfrom
claude/v2.2.0-feature-1.1.1-codex-followup

Conversation

@dreamrec

Copy link
Copy Markdown
Owner

Summary

Codex's automated review on PR #34 caught two real bugs in the v2.2.0 Phase 1.1 auto-rollback code I shipped earlier today. Both are real silent-correctness issues — neither crashes, both mislead the agent + user — and both have regression tests targeting the exact failure shapes Codex described.

This is the established v2.1.3→v2.1.4→v2.1.5 followup pattern carried into Phase 1.1.

The two bugs

P1 — rollback_fired = True claimed even when undo failed

AutoRollbackGuard.__exit__ set rollback_fired = True whenever auto_rollback_end was attempted, regardless of the handler's actual return value. Failure modes:

Dispatcher return Pre-fix behaviour Post-fix behaviour
Raises an exception rollback_fired = True + "reverted" hint (lying) rollback_fired = False + degraded hint with (undo raised: ...)
{"error": "ui.undo.endBlock failed: ..."} same as above (lying) rollback_fired = False + degraded hint with (endBlock raised: ...)
{"ok": False, "undo_error": "..."} same as above (lying) rollback_fired = False + degraded hint with the surfaced error
{"ok": True, "rolled_back": True} rollback_fired = True (correct) unchanged — correct

Worst case pre-fix: agent's follow-up decisions cascade on a corrupted graph while both the chat UI and the LLM's next tool_result show "reverted." Silent-correctness, not a crash — exactly the kind of bug that erodes trust without a clear repro.

P2 — hint dropped when undo block never opened

Agent._loop's inline hint-append condition gated on getattr(rollback_guard, "rollback_fired", False). In the degraded path (regression detected but undo block never opened — e.g. running outside TD, or auto_rollback_begin returned an error), the guard sets rollback_fired = False while still populating hint_text specifically to flag the failure. The condition dropped that hint entirely — leaving the LLM continuing from a broken graph in exactly the failure mode where it most needed feedback.

Fix: extracted the inline block into Agent._apply_rollback_hint (testable), condition now keys on hint_text presence instead of rollback_fired. Both success and degraded paths now surface the hint to LLM + chat UI uniformly.

Refactor

The inline hint-append logic became a method on Agent so the P2 path is unit-testable without urlopen mocking. Cleaner reuse surface for future Phase 1 features that also want to augment the per-batch results_block (e.g. Phase 1.3 mid-turn integrity check could fold its findings into the same callsite).

Files

Modified (3):

  • td_component/tdpilot_api_rollback.py__exit__ inspects the dispatcher's return value before claiming success; new _format_end_failure helper produces the (undo raised: …) / (endBlock raised: …) detail clauses; format_hint gained an end_failure="" keyword for richer degraded-path hints.
  • td_component/tdpilot_api_agent.py — extracted _apply_rollback_hint; _loop calls it after the per-batch tool_use loop instead of inlining the condition.
  • tests/test_tdpilot_api_rollback.py — 12 new tests across two new classes (TestCodexP1RollbackFiredAccuracy × 5, TestCodexP2HintAppendInDegradedPath × 7).

Binary (2): td_component/tdpilot_API.tox (221,182 → 222,406 bytes), .tox-api-source-hash.json — rebuilt in TD via the canonical Textport recipe.

No source files added/removed → no _SOURCE_FILES / _API_TOX_SOURCE_FILES changes needed (PR #35's paired-list consolidation means there's only one list now anyway).

Test plan

  • uv run pytest tests/ --ignore=tests/agent_evals -q1772 passed (1760 prior + 12 new).
  • uv run --extra dev ruff format --check src tests scripts td_component — clean.
  • uv run --extra dev ruff check src tests scripts td_component — clean.
  • uv run python scripts/check_versions.py — in sync at v2.1.5.
  • uv run python scripts/check_tox_freshness.py — dpsk4 .tox fresh (not touched).
  • uv run python scripts/check_tox_api_freshness.py — API .tox fresh post-rebuild (hash 10ba287545a6f421...).
  • bash scripts/check_no_personal_paths.sh — clean.
  • CI all-green on push.

No version bump — Phase 1.1 stays unreleased; this is the same in-progress arc.

Why mock-only and not live-TD verification

The user's TD has TD_MCP_REQUIRE_AUTH=1 so my MCP client hits 401, blocking live verification through the dpsk4 MCP server. The 12 new mock-dispatcher tests model the exact failure shapes Codex flagged — higher coverage than a single hand-driven live test would give. If anything still slips, the Codex review pattern will catch it post-PR.

🤖 Generated with Claude Code

dreamrec and others added 2 commits May 11, 2026 17:33
Two real bugs Codex caught on the v2.2.0 Phase 1.1 ship.

P1 — `rollback_fired = True` claimed even when undo failed
=========================================================

In `AutoRollbackGuard.__exit__`, pre-fix code set `rollback_fired =
True` whenever `auto_rollback_end` was attempted, regardless of the
handler's actual return value. Failure modes:

  * dispatcher raises (caught by `except Exception: pass`)
  * handler returns `{"error": "ui.undo.endBlock failed: ..."}`
  * handler returns `{"ok": False, "endblock_ok": True,
    "undo_error": "..."}` (the dpsk4-baked `handle_auto_rollback_end`
    explicitly returns this when `ui.undo.undo()` raises)
  * handler returns `{"ok": True}` (partial payload — defensive)

…all of these reported "reverted" to both the user and the LLM
while the network stayed broken. Silent-correctness bug, not a
crash. Worst case: agent's follow-up decisions cascade on a
corrupted graph while the chat UI shows a confident "reverted"
message.

Fix: capture the dispatcher's return value, only set rollback_fired
= True when it's `{"ok": True, "rolled_back": True}`. Every other
shape (raise, ok=False, partial) routes to the degraded hint with a
short `(undo raised: ...)` / `(endBlock raised: ...)` detail clause
appended so the LLM can decide whether to retry or escalate.

P2 — hint dropped when undo block never opened
==============================================

In `Agent._loop`, pre-fix the hint-append condition was:

    if (rollback_guard is not None
        and getattr(rollback_guard, "rollback_fired", False)
        and getattr(rollback_guard, "hint_text", "")
        and ...): ...

The middle clause keyed on `rollback_fired`. But in the degraded
path (regression detected but undo block didn't open), the guard
sets `rollback_fired = False` while still populating `hint_text`
specifically to flag the failure. The condition dropped that hint
entirely — leaving the LLM continuing from a broken graph with zero
feedback in exactly the failure mode where it most needed it.

Fix: extracted the inline block into `Agent._apply_rollback_hint`
(testable as a method), condition keys on `hint_text` presence
instead of `rollback_fired`. Both success and degraded paths now
surface the hint to LLM + chat UI uniformly.

Tests
=====

12 new regression tests in `tests/test_tdpilot_api_rollback.py`:

  TestCodexP1RollbackFiredAccuracy (5 tests)
    - end-handler returns `{"ok": False, "undo_error": ...}`
      → rollback_fired stays False, hint contains "(undo raised: ...)"
    - end-handler returns `{"error": "endBlock failed: ..."}`
      → rollback_fired stays False, hint contains "(endBlock raised: ...)"
    - dispatcher raises during auto_rollback_end
      → rollback_fired stays False, degraded hint
    - end-handler returns `{"ok": True, "rolled_back": True}` (happy path)
      → rollback_fired = True, "reverted" hint (no regression on happy path)
    - end-handler returns `{"ok": True}` (partial)
      → rollback_fired stays False (defensive)

  TestCodexP2HintAppendInDegradedPath (7 tests)
    - hint appends with rollback_fired=False (the actual P2 fix-trigger)
    - hint appends with rollback_fired=True (happy path)
    - empty hint_text is a no-op
    - None guard is a no-op
    - empty results_block is a no-op
    - list-shaped tool_result.content gets a text-block appended
    - on_text raising doesn't break the LLM-side append

Refactor
========

Extracted `Agent._loop`'s hint-append block into `Agent._apply_rollback_hint`
so the P2 path is directly testable without urlopen mocking. Also
clean reuse point for future Phase 1 features that need the same
results_block-augmentation pattern (e.g. Phase 1.3 mid-turn integrity
check might want to fold its findings into the same callsite).

Local sweep: 1772 pytest passed (1760 prior + 12 new). Ruff
format/check clean. Versions in sync. dpsk4 .tox freshness clean
(not touched). API .tox freshness FAIL until rebuilt — that's the
final pre-push step.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Bakes the rollback-success-gating fix (P1) and the extracted
Agent._apply_rollback_hint method (P2) into the .tox so users
get the corrected auto-rollback behaviour at COMP load time.

213,814 → 222,406 bytes (~+8.5KB delta from PR #34's tox —
mostly the new private method body + the broadened format_hint).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@dreamrec
dreamrec merged commit 5603d71 into main May 11, 2026
6 checks passed
dreamrec added a commit that referenced this pull request May 11, 2026
* feat(api-tox): v2.2.0 Phase 1.2 — cycle detection in tool chains

Second feature of the v2.2.0 reliability phase (Phase 1.1 was
auto-rollback; see PR #34 + Codex P1/P2 follow-up in PR #36). Pairs
with 1.1 to cover the two high-impact reliability gaps:

  - 1.1 catches "agent broke things" → undo the batch
  - 1.2 catches "agent is stuck looping" → break the turn

How it works
============

A ``CycleLedger`` is constructed once per turn in ``Agent._loop``
and tracks ``(tool_name, args_hash) -> count``. Each call to
``ledger.record(name, args)`` increments and returns the new count.
The agent loop checks against the threshold (default 3) BEFORE
dispatching:

  - count == 1: first time, dispatch.
  - count == 2: second time, dispatch.
  - count >= 3: ``CycleDetected`` raised; ``run_turn``'s catch fires
    ``on_error`` → ``EV_ERROR`` + ``EV_STATE: idle`` in the event
    stream → red banner in the chat UI with tool name + args preview.

The threshold of 3 is conservative on purpose — 2 dispatches give
the agent a chance to recover from a one-off failure before declaring
the turn stuck.

Args identity uses sorted-keys JSON so ``{"a":1,"b":2}`` and
``{"b":2,"a":1}`` collapse to the same key; nested dicts hash
recursively; lists are order-sensitive (connect source/dest
ordering matters). Disable via env var
``TDPILOT_DISABLE_CYCLE_DETECTION=1``.

Implementation
==============

- NEW td_component/tdpilot_api_cycle_detector.py — pure-Python:
  args_hash, CycleLedger, CycleDetected, env-var gate, factory
  builder. No TouchDesigner imports.

- tdpilot_api_agent.py:
  - New cycle_ledger_factory ctor kwarg.
  - _loop builds one ledger per turn after model resolution.
  - Inner per-batch for-loop checks ledger.record() BEFORE
    on_tool_call/dispatch; raises CycleDetected at the threshold.
  - CycleDetected is **late-imported** from cycle_detector inside
    _loop to avoid a circular import (cycle_detector imports
    AgentError from agent at top-level). Cost: one dict lookup per
    turn after the import is cached.

- tdpilot_api_runtime.py:
  - New _build_cycle_ledger_factory method honours
    TDPILOT_DISABLE_CYCLE_DETECTION=1.
  - AgentRuntime._build_agent passes the factory to Agent().

- build_tdpilot_api_tox.py:
  - Adds tdpilot_api_cycle_detector to _SOURCE_FILES so it's baked
    into the API .tox. (Post-#35 the freshness gate auto-imports
    this same list, so no parallel-list maintenance.)

Tests (49 new)
==============

- TestArgsHash (8) — order independence, normalization, nested
  ordering, list-order sensitivity, defensive paths.
- TestCycleLedger (10) — threshold validation (>=2), increment,
  per-key isolation, peek/reset, len semantics.
- TestCycleDetectedException (3) — metadata, message formatting,
  AgentError membership.
- TestEnvVarGate (3) — truthy/falsy classification.
- TestBuildCycleLedgerFactory (3) — env-disable, fresh instances,
  custom threshold.
- TestUsagePattern (4) — the canonical check-then-dispatch flow.
- TestFormatArgsSummary (3) — render rules.
- TestAgentLoopCycleIntegration (3) — end-to-end with mocked
  urlopen, proving the late-import + raise + on_error path
  actually works in run_turn. Covers: enabled+stuck (raises on
  3rd, dispatches 2), disabled-factory (no check, hits
  turn_budget), distinct-args (never triggers, completes cleanly).

Local sweep
===========

- pytest: 1821 passed (1772 prior + 49 new).
- ruff format + check: clean.
- check_versions: in sync at v2.1.5 (no bump on this PR).
- check_tox_freshness (dpsk4): fresh — that .tox not touched.
- check_tox_api_freshness (chat-pipe): EXPECTED FAIL until the
  user rebuilds the .tox via the canonical Textport recipe.
- check_no_personal_paths: clean.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* chore: rebuild tdpilot_API.tox for Phase 1.2 cycle detection

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
dreamrec added a commit that referenced this pull request May 11, 2026
First milestone of the v2.2.0→v3.0 roadmap (see docs/ROADMAP.md).
Phase 1 ships in full; the chat-pipe agent is now safe to leave
unsupervised on complex builds, two failure modes have automatic
recovery, and drag-and-go finally works for new users out of the box.

Bundled in this release
=======================

  - 1.1 Auto-rollback on error regression (PR #34 + #36)
  - 1.2 Cycle detection in tool chains (PR #37)
  - 1.2.1 Drag-and-go UX polish — Authmode COMP param,
    auto-save+auto-reload on Apikey change, 401 reconnect
    banner (PR #38)
  - 1.2.2 Build scripts auto-mirror .tox into main repo on rebuild,
    eliminating stale-symlink footgun (PR #39)
  - PR #35 paired source-file-list refactor (build-script + freshness-
    check now share a single source of truth)

136 new tests since v2.1.5. Total suite at release: 1848 passing.

Headline behaviour change for end users
=======================================

Default chat-pipe webserver auth posture changes from token-required
to origin-allowlist-only (Authmode=open default). The origin
allowlist still rejects cross-origin browser CSRF, so this is safe
on TouchDesigner's typical single-user dev/perform usage profile.
Users sharing .toe files across machines should set Authmode=token
on the COMP for that deployment.

The MCP-server tdpilot-dpsk4.tox (port 9985) auth model is UNCHANGED
— TD_MCP_SHARED_SECRET still required.

Bumps + rebuilt artifacts
=========================

All 10 versioned files (7 manifests + 3 doc titles) bumped from
2.1.5 to 2.2.0 (scripts/check_versions.py enforces sync). API_VERSION
in td_component/callbacks/_header.py also bumped; this invalidated
both .tox source-hashes, both rebuilt inside TouchDesigner via the
canonical recipe. Auto-mirror (Phase 1.2.2, just landed) propagated
the rebuilt .tox files to the main repo's td_component/ automatically.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@dreamrec
dreamrec deleted the claude/v2.2.0-feature-1.1.1-codex-followup branch May 11, 2026 22:48
dreamrec added a commit that referenced this pull request May 19, 2026
* fix(api-tox): Codex P1+P2 followups on auto-rollback (PR #34)

Two real bugs Codex caught on the v2.2.0 Phase 1.1 ship.

P1 — `rollback_fired = True` claimed even when undo failed
=========================================================

In `AutoRollbackGuard.__exit__`, pre-fix code set `rollback_fired =
True` whenever `auto_rollback_end` was attempted, regardless of the
handler's actual return value. Failure modes:

  * dispatcher raises (caught by `except Exception: pass`)
  * handler returns `{"error": "ui.undo.endBlock failed: ..."}`
  * handler returns `{"ok": False, "endblock_ok": True,
    "undo_error": "..."}` (the dpsk4-baked `handle_auto_rollback_end`
    explicitly returns this when `ui.undo.undo()` raises)
  * handler returns `{"ok": True}` (partial payload — defensive)

…all of these reported "reverted" to both the user and the LLM
while the network stayed broken. Silent-correctness bug, not a
crash. Worst case: agent's follow-up decisions cascade on a
corrupted graph while the chat UI shows a confident "reverted"
message.

Fix: capture the dispatcher's return value, only set rollback_fired
= True when it's `{"ok": True, "rolled_back": True}`. Every other
shape (raise, ok=False, partial) routes to the degraded hint with a
short `(undo raised: ...)` / `(endBlock raised: ...)` detail clause
appended so the LLM can decide whether to retry or escalate.

P2 — hint dropped when undo block never opened
==============================================

In `Agent._loop`, pre-fix the hint-append condition was:

    if (rollback_guard is not None
        and getattr(rollback_guard, "rollback_fired", False)
        and getattr(rollback_guard, "hint_text", "")
        and ...): ...

The middle clause keyed on `rollback_fired`. But in the degraded
path (regression detected but undo block didn't open), the guard
sets `rollback_fired = False` while still populating `hint_text`
specifically to flag the failure. The condition dropped that hint
entirely — leaving the LLM continuing from a broken graph with zero
feedback in exactly the failure mode where it most needed it.

Fix: extracted the inline block into `Agent._apply_rollback_hint`
(testable as a method), condition keys on `hint_text` presence
instead of `rollback_fired`. Both success and degraded paths now
surface the hint to LLM + chat UI uniformly.

Tests
=====

12 new regression tests in `tests/test_tdpilot_api_rollback.py`:

  TestCodexP1RollbackFiredAccuracy (5 tests)
    - end-handler returns `{"ok": False, "undo_error": ...}`
      → rollback_fired stays False, hint contains "(undo raised: ...)"
    - end-handler returns `{"error": "endBlock failed: ..."}`
      → rollback_fired stays False, hint contains "(endBlock raised: ...)"
    - dispatcher raises during auto_rollback_end
      → rollback_fired stays False, degraded hint
    - end-handler returns `{"ok": True, "rolled_back": True}` (happy path)
      → rollback_fired = True, "reverted" hint (no regression on happy path)
    - end-handler returns `{"ok": True}` (partial)
      → rollback_fired stays False (defensive)

  TestCodexP2HintAppendInDegradedPath (7 tests)
    - hint appends with rollback_fired=False (the actual P2 fix-trigger)
    - hint appends with rollback_fired=True (happy path)
    - empty hint_text is a no-op
    - None guard is a no-op
    - empty results_block is a no-op
    - list-shaped tool_result.content gets a text-block appended
    - on_text raising doesn't break the LLM-side append

Refactor
========

Extracted `Agent._loop`'s hint-append block into `Agent._apply_rollback_hint`
so the P2 path is directly testable without urlopen mocking. Also
clean reuse point for future Phase 1 features that need the same
results_block-augmentation pattern (e.g. Phase 1.3 mid-turn integrity
check might want to fold its findings into the same callsite).

Local sweep: 1772 pytest passed (1760 prior + 12 new). Ruff
format/check clean. Versions in sync. dpsk4 .tox freshness clean
(not touched). API .tox freshness FAIL until rebuilt — that's the
final pre-push step.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* chore: rebuild tdpilot_API.tox for Codex P1+P2 followups

Bakes the rollback-success-gating fix (P1) and the extracted
Agent._apply_rollback_hint method (P2) into the .tox so users
get the corrected auto-rollback behaviour at COMP load time.

213,814 → 222,406 bytes (~+8.5KB delta from PR #34's tox —
mostly the new private method body + the broadened format_hint).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
dreamrec added a commit that referenced this pull request May 19, 2026
* feat(api-tox): v2.2.0 Phase 1.2 — cycle detection in tool chains

Second feature of the v2.2.0 reliability phase (Phase 1.1 was
auto-rollback; see PR #34 + Codex P1/P2 follow-up in PR #36). Pairs
with 1.1 to cover the two high-impact reliability gaps:

  - 1.1 catches "agent broke things" → undo the batch
  - 1.2 catches "agent is stuck looping" → break the turn

How it works
============

A ``CycleLedger`` is constructed once per turn in ``Agent._loop``
and tracks ``(tool_name, args_hash) -> count``. Each call to
``ledger.record(name, args)`` increments and returns the new count.
The agent loop checks against the threshold (default 3) BEFORE
dispatching:

  - count == 1: first time, dispatch.
  - count == 2: second time, dispatch.
  - count >= 3: ``CycleDetected`` raised; ``run_turn``'s catch fires
    ``on_error`` → ``EV_ERROR`` + ``EV_STATE: idle`` in the event
    stream → red banner in the chat UI with tool name + args preview.

The threshold of 3 is conservative on purpose — 2 dispatches give
the agent a chance to recover from a one-off failure before declaring
the turn stuck.

Args identity uses sorted-keys JSON so ``{"a":1,"b":2}`` and
``{"b":2,"a":1}`` collapse to the same key; nested dicts hash
recursively; lists are order-sensitive (connect source/dest
ordering matters). Disable via env var
``TDPILOT_DISABLE_CYCLE_DETECTION=1``.

Implementation
==============

- NEW td_component/tdpilot_api_cycle_detector.py — pure-Python:
  args_hash, CycleLedger, CycleDetected, env-var gate, factory
  builder. No TouchDesigner imports.

- tdpilot_api_agent.py:
  - New cycle_ledger_factory ctor kwarg.
  - _loop builds one ledger per turn after model resolution.
  - Inner per-batch for-loop checks ledger.record() BEFORE
    on_tool_call/dispatch; raises CycleDetected at the threshold.
  - CycleDetected is **late-imported** from cycle_detector inside
    _loop to avoid a circular import (cycle_detector imports
    AgentError from agent at top-level). Cost: one dict lookup per
    turn after the import is cached.

- tdpilot_api_runtime.py:
  - New _build_cycle_ledger_factory method honours
    TDPILOT_DISABLE_CYCLE_DETECTION=1.
  - AgentRuntime._build_agent passes the factory to Agent().

- build_tdpilot_api_tox.py:
  - Adds tdpilot_api_cycle_detector to _SOURCE_FILES so it's baked
    into the API .tox. (Post-#35 the freshness gate auto-imports
    this same list, so no parallel-list maintenance.)

Tests (49 new)
==============

- TestArgsHash (8) — order independence, normalization, nested
  ordering, list-order sensitivity, defensive paths.
- TestCycleLedger (10) — threshold validation (>=2), increment,
  per-key isolation, peek/reset, len semantics.
- TestCycleDetectedException (3) — metadata, message formatting,
  AgentError membership.
- TestEnvVarGate (3) — truthy/falsy classification.
- TestBuildCycleLedgerFactory (3) — env-disable, fresh instances,
  custom threshold.
- TestUsagePattern (4) — the canonical check-then-dispatch flow.
- TestFormatArgsSummary (3) — render rules.
- TestAgentLoopCycleIntegration (3) — end-to-end with mocked
  urlopen, proving the late-import + raise + on_error path
  actually works in run_turn. Covers: enabled+stuck (raises on
  3rd, dispatches 2), disabled-factory (no check, hits
  turn_budget), distinct-args (never triggers, completes cleanly).

Local sweep
===========

- pytest: 1821 passed (1772 prior + 49 new).
- ruff format + check: clean.
- check_versions: in sync at v2.1.5 (no bump on this PR).
- check_tox_freshness (dpsk4): fresh — that .tox not touched.
- check_tox_api_freshness (chat-pipe): EXPECTED FAIL until the
  user rebuilds the .tox via the canonical Textport recipe.
- check_no_personal_paths: clean.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* chore: rebuild tdpilot_API.tox for Phase 1.2 cycle detection

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
dreamrec added a commit that referenced this pull request May 19, 2026
First milestone of the v2.2.0→v3.0 roadmap (see docs/ROADMAP.md).
Phase 1 ships in full; the chat-pipe agent is now safe to leave
unsupervised on complex builds, two failure modes have automatic
recovery, and drag-and-go finally works for new users out of the box.

Bundled in this release
=======================

  - 1.1 Auto-rollback on error regression (PR #34 + #36)
  - 1.2 Cycle detection in tool chains (PR #37)
  - 1.2.1 Drag-and-go UX polish — Authmode COMP param,
    auto-save+auto-reload on Apikey change, 401 reconnect
    banner (PR #38)
  - 1.2.2 Build scripts auto-mirror .tox into main repo on rebuild,
    eliminating stale-symlink footgun (PR #39)
  - PR #35 paired source-file-list refactor (build-script + freshness-
    check now share a single source of truth)

136 new tests since v2.1.5. Total suite at release: 1848 passing.

Headline behaviour change for end users
=======================================

Default chat-pipe webserver auth posture changes from token-required
to origin-allowlist-only (Authmode=open default). The origin
allowlist still rejects cross-origin browser CSRF, so this is safe
on TouchDesigner's typical single-user dev/perform usage profile.
Users sharing .toe files across machines should set Authmode=token
on the COMP for that deployment.

The MCP-server tdpilot-dpsk4.tox (port 9985) auth model is UNCHANGED
— TD_MCP_SHARED_SECRET still required.

Bumps + rebuilt artifacts
=========================

All 10 versioned files (7 manifests + 3 doc titles) bumped from
2.1.5 to 2.2.0 (scripts/check_versions.py enforces sync). API_VERSION
in td_component/callbacks/_header.py also bumped; this invalidated
both .tox source-hashes, both rebuilt inside TouchDesigner via the
canonical recipe. Auto-mirror (Phase 1.2.2, just landed) propagated
the rebuilt .tox files to the main repo's td_component/ automatically.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant