Skip to content

Live Stream: derive Anchor-owned file artifacts - #6207

Open
franksong2702 wants to merge 22 commits into
nesquena:masterfrom
franksong2702:franksong2702/live-stream-artifact-reference-derivation
Open

franksong2702 wants to merge 22 commits into
nesquena:masterfrom
franksong2702:franksong2702/live-stream-artifact-reference-derivation

Conversation

@franksong2702

@franksong2702 franksong2702 commented Jul 18, 2026

Copy link
Copy Markdown
Contributor

Thinking Path

  • The Live-to-Final contract already classifies artifact_reference, but successful Hermes file tools did not produce a durable, turn-owned artifact event.
  • Inferring success in the browser is unsafe because the backend owns the complete tool result and the workspace boundary.
  • The producer, journal replay, terminal settlement, and reload paths must agree; otherwise artifacts disappear when the browser disconnects, a turn is cancelled, or settlement races with a browser POST.

What Changed

  • Derive path-only artifact references from proven successful write_file and patch results.
  • Reject malformed results, unsafe/non-canonical workspace paths, traversal, symlink escapes, foreign drive paths, URLs, ignored generated trees, and oversized input.
  • Emit bounded artifact_reference events after tool_complete and retain the exact run/stream owner through the run journal.
  • Persist a deterministic 64-event / 32-KiB bounded artifact prefix across completion, returned errors, cancellation, background settlement, reconnect, and reload.
  • Merge browser and worker settlement symmetrically under server-owned session/run/stream authority.
  • Route artifacts into the Assistant Turn Anchor without adding Worklog rows or repainting the live transcript.
  • Add producer, lifecycle, ownership, budget, replay, cancellation, and persistence regression coverage.

Fixes #6205.
Refs #3400.

Why It Matters

Files produced by a turn remain attached to that same assistant turn even when Live Stream transitions to Final Answer without a connected browser. The backend records only bounded workspace-relative metadata; it never persists file bodies or raw tool results in the Anchor scene.

Release note: Preserve turn-owned file artifact references from successful file tools across streaming, terminal settlement, reconnect, and reload.

Verification

  • ./scripts/test.sh tests/test_live_anchor_artifact_reference.py tests/test_anchor_scene_persistence.py tests/test_sse_relay_apperror_closes.py --tb=short -q -> 79 passed.
  • Adjacent Anchor/run-journal/session suites -> 167 passed.
  • Adjacent streaming/settlement suites -> 73 passed, 1 skipped.
  • Full repository run -> 13,831 passed, 113 skipped, 1 xfailed, 2 xpassed. The one PR-sensitive legacy cancellation assertion was fixed and is included in the 79-pass gate above; the remaining isolated failures reproduce unchanged on origin/master@dd7f6ac318 in the same environment.
  • python scripts/ruff_lint.py --diff origin/master -> 0 findings on added/modified lines.
  • npm run --silent lint:runtime -> passed.
  • Python byte compilation and git diff --check origin/master -> passed.

Risks / Follow-ups

  • Only canonical Hermes write_file and patch result schemas are recognized. Shell, code, and dynamic MCP side effects remain out of scope because their mutations cannot be proven from command text.
  • This PR provides durable ownership metadata. It does not add a new Artifact UI or change Final Answer presentation, so there is no new visual layout to screenshot.
  • Existing Artifact-tab reconstruction and large-file preview limits are unchanged.

Model Used

  • OpenAI Codex gpt-5.6-sol implemented and self-reviewed the rebuild.
  • OpenAI Codex gpt-5.6-luna performed an independent read-only scope and correctness review.

Contract Routing

Task type: implementing the accepted Live-to-Final artifact-ownership contract.

Touched areas:

  • Hermes file-tool result classification
  • run-journal SSE production and replay
  • Assistant Turn Anchor artifact ownership
  • terminal scene settlement and reload hydration

Relevant docs:

  • AGENTS.md
  • CONTRIBUTING.md
  • docs/CONTRACTS.md
  • docs/rfcs/live-to-final-assistant-replies.md
  • docs/rfcs/stable-assistant-turn-anchors.md
  • docs/architecture/stable-assistant-turn-anchor-phase0.md

State invariant: proven tool mutation -> bounded workspace-relative artifact_reference -> run journal -> exact Assistant Turn owner -> renderer-neutral activity_scene_v1, without becoming a Compact Worklog row.

Contract Change

Previous state: the Anchor model classified artifact references, but production file mutations did not emit or durably settle them.

New state: successful canonical file mutations produce bounded, server-validated artifact references that survive all terminal and reload paths.

Compatibility: additive metadata only. Existing tool cards, final-answer rendering, and Artifact-tab behavior remain unchanged.

@greptile-apps

greptile-apps Bot commented Jul 18, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR closes the gap between successful Hermes file-tool mutations and durable turn-owned artifact records by deriving workspace-relative artifact_reference events from proven write_file/patch results, journaling them through the run journal, and persisting a 64-event / 32-KiB bounded artifact prefix that survives streaming, cancellation, background settlement, reconnect, and reload.

  • api/artifact_references.py (new): all derivation, sanitization, owner-mismatch validation, and scene-merge logic lives here; bytes_written is strictly checked (type(…) is int and … >= 0), dist/build are root-only exclusions, and path traversal / URL / symlink guards are thorough.
  • api/streaming.py: two mutually-exclusive derivation sites (the tool.completed event path guards with an early return when tool_complete_callback is registered); _reconcile_stream_artifacts_into_terminal_anchor_scene covers all terminal paths (error, cancel, completed) with server-owned records.
  • api/routes.py: _handle_session_anchor_scene uses a double-lock pattern with an intervening lock-free journal read; workspace digest is re-verified at the second lock and a 409 is returned on drift; journal truncation fails closed for artifact authority.

Confidence Score: 5/5

  • Safe to merge. All terminal paths are covered by server-side reconciliation before session save, and the browser settlement path fails closed when journal evidence is absent or truncated.
  • The change is additive: it derives and persists bounded metadata without altering final-answer rendering, tool cards, or the compact worklog. The double-lock pattern in the anchor-persistence handler correctly detects workspace drift between evidence reads. Fail-closed paths (truncated journal → empty artifacts, missing workspace → early return, non-server artifact_authority → cleared artifacts) are consistently applied across streaming, settlement, and reload. The existing concerns from prior review threads (bytes_written strictness, dist/build root-only, owner_authority flag) have all been addressed in this revision. Test coverage spans producer, lifecycle, ownership, budget, replay, cancellation, and persistence scenarios.
  • No files require special attention. The most complex logic is in api/artifact_references.py and the _handle_session_anchor_scene handler in api/routes.py; both are well-covered by the new test suites.

Important Files Changed

Filename Overview
api/artifact_references.py New module providing bounded artifact-reference derivation, sanitization, deduplication, owner-mismatch validation, and scene-merge logic. The bytes_written check (type(bytes_written) is int and bytes_written >= 0) is strict and correctly distinguishes falsy/null values. The dist/build exclusion is correctly root-only via _IGNORED_ROOT_PATH_PARTS. Path-traversal, symlink-escape, URL, and foreign-drive guards are thorough. JSON size budgeting uses a hand-written stack-based walk that handles circular references and nesting depth.
api/streaming.py Integrates artifact derivation into the live-stream producer. The two derivation sites (tool.completed event path and on_tool_complete callback) are mutually exclusive thanks to the early-return guard at line 9353. The tool.completed path lacks tool_call_id (not available in cb_kwargs for this protocol) — this is a documented limitation similar to the on_tool path. Cancel-surviving artifact_reference events, in-memory _anchor_artifact_events tracking, and _reconcile_stream_artifacts_into_terminal_anchor_scene call-sites cover all terminal paths.
api/routes.py Rewrites _handle_session_anchor_scene to use a double-lock pattern: first lock resolves workspace and message identity, then journal evidence is read lock-free, then second lock revalidates and commits. Workspace identity digest is checked for consistency between both locks (409 on drift). Journal truncation fails closed for artifacts (journal_truncated skips artifact_references in replay). The _hydrate_anchor_activity_scenes reload path validates artifact workspace authority against the current session digest before retaining stored artifacts.
api/run_journal.py Adds max_bytes/max_rows bounded reading to _read_jsonl with explicit truncated flag. The readline(remaining+1) sentinel correctly distinguishes a line that exactly fits (not truncated) from one that overflows (truncated). The stat() fallback for byte-limit detection is guarded against OSError. The truncated flag propagates through read_run_events so callers can fail closed for security-sensitive operations.
static/assistant_turn_anchors.js Adds _boundedAnchorArtifactEvents with deduplication and 64-event/32-KiB cap mirroring the Python budget. Replaces direct array push with _appendBoundedAnchorArtifact to enforce the cap during live stream accumulation. Reload hydration now applies applySnapshotEvent for artifact rows in addition to activity rows.
static/messages.js Adds artifact_reference SSE event listener (render:false) so live artifacts update the anchor without repainting the transcript. _boundedAnchorSceneArtifacts / _boundedAnchorSceneForPersistence apply the same client-side 64-event/32-KiB cap before POSTing to /anchor. hasAnchorActivityScene check extended to treat a non-empty artifacts array as a live scene even with no activity_rows.
static/sessions.js Single-line change extends hasAnchorActivityScene to consider a non-empty artifacts list even when activity_rows is empty, ensuring reload treats an artifact-only scene as a valid live snapshot.
tests/test_live_anchor_artifact_reference.py Comprehensive producer and lifecycle regression tests covering: strict bytes_written validation (null/bool/float/negative), path-traversal/symlink/URL rejection, root-level dist/build exclusion vs nested build allowed, budget overflow, cancel-surviving artifact events, and JavaScript budget parity via Node subprocess. The _function_block helper relies on fixed 12-space indentation — documented risk in prior review but not blocking.
tests/test_anchor_scene_persistence.py Tests anchor-scene persistence with artifact ownership, workspace-digest validation, double-lock conflict detection (409), and server-authority propagation. Covers both pre-existing authoritative records and first-settlement paths.

Sequence Diagram

sequenceDiagram
    participant Agent as Hermes Agent
    participant Stream as _run_agent_streaming
    participant Journal as Run Journal
    participant SSE as SSE Queue
    participant Browser as Browser
    participant Routes as /session/anchor
    participant Session as Session Store

    Agent->>Stream: tool_complete (write_file/patch)
    Stream->>Stream: derive_file_artifact_references()
    Stream->>Stream: _anchor_artifact_reference_with_workspace()
    Stream->>Stream: budget check (_anchor_artifact_reference_within_stream_budget)
    Stream->>Journal: put('artifact_reference', payload)
    Journal-->>Stream: event_id
    Stream->>Stream: _record_anchor_artifact_reference(event_id)
    Stream->>SSE: artifact_reference event

    Note over Stream,Session: Terminal settlement path
    Stream->>Session: _reconcile_stream_artifacts_into_terminal_anchor_scene()
    Session->>Session: merge_anchor_activity_scene()
    Session->>Session: "save anchor_activity_scenes[key] {owner_authority: server}"

    Note over Browser,Routes: Browser settlement path
    SSE-->>Browser: artifact_reference SSE event
    Browser->>Browser: "_applyToAnchor('artifact_reference', {render:false})"
    Browser->>Browser: _boundedAnchorArtifactEvents()
    Browser->>Routes: "POST /session/{id}/anchor {scene: {artifacts: [...]}}"
    Routes->>Journal: _run_journal_live_snapshot(stream_id)
    Note over Routes,Journal: Read bounded journal for authority evidence
    Routes->>Routes: retain_server_authoritative_artifact_events()
    Routes->>Routes: merge_anchor_activity_scene()
    Routes->>Session: "save anchor_activity_scenes[ref] {artifact_authority: server}"

    Note over Browser,Session: Reload hydration
    Browser->>Routes: "GET /session/{id}"
    Routes->>Session: _hydrate_anchor_activity_scenes()
    Routes->>Routes: validate workspace_id digest match
    Routes->>Routes: retain_server_authoritative_artifact_events()
    Routes-->>Browser: messages with _anchor_activity_scene.artifacts
Loading

Reviews (84): Last reviewed commit: "chore: refresh PR 6207 onto master" | Re-trigger Greptile

Comment thread api/streaming.py Outdated
Comment thread api/artifact_references.py Outdated
Comment thread tests/test_live_anchor_artifact_reference.py
@franksong2702

Copy link
Copy Markdown
Contributor Author

Aftercare follow-up pushed in b5f4f77:

  • Refreshed the branch onto current master (b470793).
  • Narrowed the generic build/dist artifact filter to root-level generated trees, while keeping VCS/cache/dependency directories rejected by path component. Added a regression so docs/build/report.md remains a valid workspace artifact but root build output is still excluded.
  • Left the legacy on_tool artifact event without tool_call_id intentionally: Hermes Agent's legacy tool_progress_callback carries result/duration/error but no stable call id. The modern structured on_tool_complete path still attaches tool_call_id; synthesizing one for legacy would not bind to a real tool_complete id.

Local verification for the follow-up:

  • ./scripts/test.sh tests/test_live_anchor_artifact_reference.py (7 passed)
  • .venv/bin/python -m py_compile api/artifact_references.py api/streaming.py
  • git diff --check

@franksong2702

Copy link
Copy Markdown
Contributor Author

Base refresh pushed in e1cf64a:

  • Merged current origin/master at ab937ef (release PR Release: msg_limit ceiling metadata decoupling (#6214, @webtecnica) #6216) into Frank's PR branch; merge was clean with no manual conflict resolution.
  • Local verification after the merge:
    • ./scripts/test.sh tests/test_live_anchor_artifact_reference.py (7 passed)
    • .venv/bin/python -m py_compile api/artifact_references.py api/streaming.py
    • git diff --check

GitHub Actions and Greptile have restarted on the new head; no Frank action is needed.

@franksong2702

Copy link
Copy Markdown
Contributor Author

Base refresh pushed in 3c4842e:

  • Merged current origin/master at 52c962c (release PR Release: Transparent Stream multi-segment prefix dedupe (#6189, @ai-ag2026) #6217) into Frank's PR branch; merge was clean with no manual conflict resolution.
  • Because the incoming base touched static/messages.js, I verified both this PR's artifact-reference coverage and the incoming transparent-stream prefix-dedupe coverage:
    • ./scripts/test.sh tests/test_live_anchor_artifact_reference.py tests/test_5749_anchor_scene_client_prefix_dedupe.py tests/test_issue5749_transparent_stream_prefix_dedupe.py (18 passed)
    • .venv/bin/python -m py_compile api/artifact_references.py api/streaming.py
    • git diff --check

GitHub checks have restarted on the new head; no Frank action is needed.

@nesquena-hermes nesquena-hermes added the size:L Large PR (>10 files or >250 LOC) label Jul 18, 2026
@franksong2702

Copy link
Copy Markdown
Contributor Author

Base refresh pushed in c6dffcb:

  • Merged current origin/master at 02aa91b (release PR Release: stop false Compressing-context card (#6184, @carlotestor) #6223) into Frank's PR branch; merge was clean with no manual conflict resolution.
  • The incoming base touched api/streaming.py and static/messages.js, so I verified this PR's artifact-reference coverage plus the incoming auto-compression card coverage:
    • ./scripts/test.sh tests/test_live_anchor_artifact_reference.py tests/test_auto_compression_card.py (74 passed)
    • .venv/bin/python -m py_compile api/artifact_references.py api/streaming.py
    • git diff --check

GitHub checks and Greptile have restarted on the new head; no Frank action is needed.

@franksong2702

Copy link
Copy Markdown
Contributor Author

Base refresh pushed in 180dc6a:

  • Merged current origin/master at 735ba1c (release PR Release: extension session-open handler + renderTranscript API (#5508, @ChonSong) #6226) into Frank's PR branch; merge was clean with no manual conflict resolution.
  • The incoming base touched static/boot.js, static/sessions.js, and extension-session tests, so I verified this PR's artifact-reference coverage plus the incoming extension/session coverage:
    • ./scripts/test.sh tests/test_live_anchor_artifact_reference.py tests/test_extension_session_hooks.py tests/test_issue1611_session_profile_filtering.py (50 passed)
    • .venv/bin/python -m py_compile api/artifact_references.py api/streaming.py
    • git diff --check

GitHub checks and Greptile have restarted on the new head; no Frank action is needed.

@franksong2702

Copy link
Copy Markdown
Contributor Author

Proof-matrix aftercare at d2364c75a: added the explicit foreign-drive rejection case required by #6205 (C:\\... must not be treated as workspace-relative on POSIX). Focused gate: 24 passed, including success/failure, containment, symlink escape, ordering, cancellation journalability, and frontend routing. This follow-up is test-only; production behavior is unchanged.

@franksong2702

Copy link
Copy Markdown
Contributor Author

Base refresh pushed in 388575f:

  • Merged current origin/master at 92a7189 (release PR Release: durable run-journal recovery + full tool args (#6197, @franksong2702) #6236) into Frank's PR branch; merge was clean with no manual conflict resolution.
  • The incoming base touched run-journal recovery / full tool args paths and auto-merged static/messages.js, so I verified this PR's artifact-reference coverage plus neighboring run-journal and gateway stream recovery coverage:
    • ./scripts/test.sh tests/test_live_anchor_artifact_reference.py tests/test_inflight_stream_reuse.py tests/test_run_journal_routes.py tests/test_webui_gateway_chat_backend.py tests/test_cross_session_message_load_isolation.py (111 passed)
    • .venv/bin/python -m py_compile api/artifact_references.py api/streaming.py api/run_journal.py api/routes.py api/gateway_chat.py
    • git diff --check

GitHub checks have restarted on the new head; no Frank action is needed.

@franksong2702

Copy link
Copy Markdown
Contributor Author

Base refresh pushed in a86ce5b:

  • Merged current origin/master at a4a2f49 (release PR Release: folder-download subpath baseURI fix (#6227, @steezypunk) #6237) into Frank's PR branch; merge was clean with no manual conflict resolution.
  • The incoming base only touched CHANGELOG.md and static/ui.js for the folder-download subpath baseURI fix, so I verified this PR's artifact-reference coverage plus the affected folder-download coverage:
    • ./scripts/test.sh tests/test_live_anchor_artifact_reference.py tests/test_folder_download.py (19 passed)
    • .venv/bin/python -m py_compile api/artifact_references.py api/streaming.py
    • git diff --check

GitHub checks have restarted on the new head; no Frank action is needed.

@franksong2702

Copy link
Copy Markdown
Contributor Author

Base refresh pushed in 009e517:

  • Merged current origin/master at d195b09 (release PR Release: GLM per-version reasoning controls (#6219, @rh-id) #6243) into Frank's PR branch; merge was clean with no manual conflict resolution.
  • The incoming base touched GLM per-version reasoning controls in api/config.py, static/index.html, static/ui.js, and reasoning tests, so I verified this PR's artifact-reference coverage plus the affected reasoning coverage:
    • ./scripts/test.sh tests/test_live_anchor_artifact_reference.py tests/test_reasoning_chip_js_behaviour.py tests/test_reasoning_show_hide.py tests/test_zai_reasoning_effort_gating.py (138 passed)
    • .venv/bin/python -m py_compile api/artifact_references.py api/streaming.py api/config.py
    • git diff --check

GitHub checks and Greptile have restarted on the new head; no Frank action is needed.

@franksong2702

Copy link
Copy Markdown
Contributor Author

Base refresh pushed in 7eaf437:

  • Merged current origin/master at 0a31a4a (release PR Release: intercept /sessions and /resume slash commands (#6245, @webtecnica) #6253) into Frank's PR branch; merge was clean with no manual conflict resolution.
  • The incoming base touched static/messages.js for native /sessions and /resume slash-command interception, so I verified this PR's artifact-reference coverage plus neighboring slash-command send-path coverage:
    • ./scripts/test.sh tests/test_live_anchor_artifact_reference.py tests/test_cli_only_slash_commands.py tests/test_issue840_slash_echo.py (50 passed)
    • .venv/bin/python -m py_compile api/artifact_references.py api/streaming.py
    • node --check static/messages.js
    • git diff --check

GitHub checks and Greptile have restarted on the new head; no Frank action is needed.

@franksong2702

Copy link
Copy Markdown
Contributor Author

Base refresh pushed in 90b8513:

  • Merged current origin/master at c428452 (release PR Release: OIDC allowlist whitespace fix (#6244, @webtecnica) #6259) into Frank's PR branch; merge was clean with no manual conflict resolution.
  • The incoming base touched api/auth_oidc.py and tests/test_issue3825_oidc_auth.py for the OIDC allowlist whitespace fix, so I verified this PR's artifact-reference coverage plus the affected OIDC coverage:
    • ./scripts/test.sh tests/test_live_anchor_artifact_reference.py tests/test_issue3825_oidc_auth.py (33 passed)
    • .venv/bin/python -m py_compile api/artifact_references.py api/streaming.py api/auth_oidc.py
    • git diff --check

GitHub checks and Greptile have restarted on the new head; no Frank action is needed.

@franksong2702

Copy link
Copy Markdown
Contributor Author

Base refresh pushed in c173e27:

  • Merged current origin/master at c9deb98 (release PR Release: remove dead rowIndex param from settled-scene pushRow (#6258, @webtecnica) #6262) into Frank's PR branch; merge was clean with no manual conflict resolution.
  • The incoming base touched static/messages.js and tests/test_live_to_final_anchor_visible_order.py for the settled-scene pushRow cleanup, so I verified this PR's artifact-reference coverage plus the affected Live-to-Final anchor ordering coverage:
    • ./scripts/test.sh tests/test_live_anchor_artifact_reference.py tests/test_live_to_final_anchor_visible_order.py (71 passed)
    • .venv/bin/python -m py_compile api/artifact_references.py api/streaming.py
    • node --check static/messages.js
    • git diff --check

GitHub checks and Greptile have restarted on the new head; no Frank action is needed.

@franksong2702

Copy link
Copy Markdown
Contributor Author

Base refresh pushed in 3911bd3:

  • Merged current origin/master at 69ffaf3 (release PR Release: byte-size threshold for reconnect tail optimization (#6260, @webtecnica) #6263) into Frank's PR branch; merge was clean with no manual conflict resolution.
  • The incoming base touched api/routes.py for the byte-size reconnect tail optimization, so I verified this PR's artifact-reference coverage plus the affected state-db limited-display/reconnect tail coverage:
    • ./scripts/test.sh tests/test_live_anchor_artifact_reference.py tests/test_webui_state_db_reconciliation.py (55 passed)
    • .venv/bin/python -m py_compile api/artifact_references.py api/streaming.py api/routes.py
    • git diff --check

GitHub checks and Greptile have restarted on the new head; no Frank action is needed.

@nesquena-hermes

Copy link
Copy Markdown
Collaborator

Reviewed at head 3911bd3d1 (own worktree, tests run). Verdict: CLEAN (2 optional non-blocking notes).

Verified fail-closed derivation, path-only emission, and traversal/symlink containment against the real tool-result contract; ran the suite (8/8 pass) and confirmed coverage is genuine by breaking the fail-closed check and watching test_failed_incomplete_or_read_only_results_do_not_become_artifacts redden.

  • Fail-closed correctnessderive_file_artifact_references proves the mutation from the raw result payload (not the callback's unconditional is_error:false): only write_file/patch in _MUTATION_TOOL_NAMES, _mutation_landed requires bytes_written (write_file) / success is True (patch), rejects on error / missing / unparseable → []. Old builds without a structured result fall back to a truncated preview that fails json.loads → no artifact (degrades like todo_state).
  • Path-only / no body leak — reference dict is {kind, path, source_tool, tool_call_id} only; test asserts input body, output body, and absolute path are all absent from the encoded event.
  • Traversal/symlink_workspace_relative_path does resolve-then-relative_to (escaping symlink resolves outside → ValueErrorNone); also rejects NUL/newline/://, >4096 chars, POSIX-side drive paths, and filters .git/.venv/node_modules. Covered by test_existing_symlink_escape_is_rejected + test_foreign_drive_path_is_rejected_on_posix.
  • No streaming regressionseen set is per-call-local; double-emit prevented by the existing tool_complete_callback early-return (legacy :7880 vs modern :8000 mutually exclusive); the cancel-guard widening to allow artifact_reference is gated by _success_writeback_committed.

Two optional notes, neither blocking: (1) derive_file_artifact_references does filesystem I/O via Path.resolve() — side-effect-free but not "pure"; worth a docstring note. (2) The V4A fallback emits Delete File/Move File source paths as owned workspace_file artifacts even though they no longer exist, and files_modified iteration is uncapped — worth considering whether a deleted-source path should surface as owned, and a sane length cap. Thanks @franksong2702.

@franksong2702

Copy link
Copy Markdown
Contributor Author

Base refresh pushed in d7d01a4:

  • Merged current origin/master at bbb5446 (release PR Release: deduplicate configured model badges (#6221, @happy5318) #6268) into Frank's PR branch; merge was clean with no manual conflict resolution.
  • The incoming base touched static/ui.js and configured-model picker tests, so I verified this PR's artifact-reference coverage plus the affected model-picker coverage:
    • ./scripts/test.sh tests/test_live_anchor_artifact_reference.py tests/test_configured_model_picker_dedup.py tests/test_configured_model_picker_provider_routing.py tests/test_issue3691_model_picker_show_all.py (26 passed)
    • .venv/bin/python -m py_compile api/artifact_references.py api/streaming.py
    • node --check static/messages.js
    • node --check static/ui.js
    • git diff --check

Thanks for the clean review on 3911bd3. I’m leaving the two optional notes as non-blocking for this PR:

  • The Path.resolve() filesystem check is intentional at the derivation boundary because it lets the path guard reject symlink escapes before emitting an artifact_reference payload. I agree the wording can avoid implying pure no-filesystem computation.
  • I’m not changing V4A delete/move fallback semantics here because that would expand the artifact ownership contract beyond this PR’s proven canonical write_file/patch landed-file path. If maintainers want deleted-source paths surfaced differently, I’d handle that as a separate scoped follow-up.

GitHub checks and Greptile have restarted on the new head; no Frank action is needed.

@franksong2702

Copy link
Copy Markdown
Contributor Author

Base refresh pushed in ebfc1b4:

  • Merged current origin/master at be45c39 (release PR Release: render data:image URIs as images (#6209, @ai-ag2026) #6270) into Frank's PR branch; merge was clean with no manual conflict resolution.
  • The incoming base touched static/messages.js/static/ui.js for data:image URI rendering, so I verified this PR's artifact-reference coverage plus the affected renderer/streaming markdown coverage:
    • ./scripts/test.sh tests/test_live_anchor_artifact_reference.py tests/test_data_uri_images.py tests/test_issue6209_data_image_renderer.py tests/test_streaming_markdown.py (83 passed)
    • .venv/bin/python -m py_compile api/artifact_references.py api/streaming.py
    • node --check static/messages.js
    • node --check static/ui.js
    • git diff --check

GitHub checks and Greptile have restarted on the new head; no Frank action is needed.

@franksong2702

Copy link
Copy Markdown
Contributor Author

Base refresh pushed in be9986d:

  • Merged current origin/master at 9451445 (release PR docs(changelog): stamp v0.52.76 #6269) into Frank's PR branch; merge was clean with no manual conflict resolution.
  • The incoming base was changelog-only, so I verified this PR's artifact-reference coverage and basic syntax/whitespace:
    • ./scripts/test.sh tests/test_live_anchor_artifact_reference.py (8 passed)
    • .venv/bin/python -m py_compile api/artifact_references.py api/streaming.py
    • git diff --check

GitHub checks and Greptile have restarted on the new head; no Frank action is needed.

@franksong2702

Copy link
Copy Markdown
Contributor Author

Base refresh pushed in 942f930:

  • Merged current origin/master at 2ea0cc6 (release PR ci: docs-only fast-path + minimal docs CI #6279) into Frank's PR branch; merge was clean with no manual conflict resolution.
  • The incoming base touched CI workflows and the new critical markdown checker, so I verified this PR's artifact-reference coverage plus the incoming checker coverage:
    • ./scripts/test.sh tests/test_live_anchor_artifact_reference.py scripts/test_critical_markdown_check.py (41 passed, 28 skipped)
    • .venv/bin/python -m py_compile api/artifact_references.py api/streaming.py scripts/critical_markdown_check.py
    • git diff --check

GitHub checks and Greptile have restarted on the new head; no Frank action is needed.

@franksong2702

Copy link
Copy Markdown
Contributor Author

Base refresh pushed in f0293d7:

  • Merged current origin/master at b324eb9 (release PR Release: prevent bare-id picker revert on empty provider hint (#6199, @webtecnica) #6280) into Frank's PR branch; merge was clean with no manual conflict resolution.
  • The incoming base touched static/ui.js and model-picker/runtime-guard tests, so I verified this PR's artifact-reference coverage plus the affected picker coverage:
    • ./scripts/test.sh tests/test_live_anchor_artifact_reference.py tests/test_agent_runtime_revision_guard.py tests/test_issue2720_bedrock_model_picker.py tests/test_issue6195_bare_id_ambiguous_no_revert.py tests/test_provider_sort_order.py (44 passed)
    • .venv/bin/python -m py_compile api/artifact_references.py api/streaming.py
    • node --check static/ui.js
    • git diff --check

GitHub checks and Greptile have restarted on the new head; no Frank action is needed.

@franksong2702

Copy link
Copy Markdown
Contributor Author

Base refresh pushed in 47e9da1a1.

Verification:

  • ./scripts/test.sh tests/test_live_anchor_artifact_reference.py tests/test_stable_assistant_turn_anchor_phase0.py tests/test_stable_assistant_turn_anchor_normalizer.py tests/test_todo_live_frontend_static.py tests/test_workspace_subpath_raw_urls.py tests/test_session_attention_badges.py tests/test_session_touch_actions.py -> 54 passed
  • .venv/bin/python -m py_compile api/artifact_references.py api/streaming.py
  • node --check static/messages.js
  • node --check static/sessions.js
  • node --check static/workspace.js
  • git diff --check

GitHub checks and Greptile have restarted on the new head; no Frank action is needed.

@franksong2702

Copy link
Copy Markdown
Contributor Author

Base refresh pushed in f1d19ea4a.

Verification:

  • ./scripts/test.sh tests/test_live_anchor_artifact_reference.py tests/test_async_delegation_webui_bridge.py tests/test_notify_on_complete_webui.py tests/test_xsession_wakeup_misroute.py -> 59 passed
  • .venv/bin/python -m py_compile api/artifact_references.py api/streaming.py api/background_process.py api/process_event_utils.py
  • node --check static/messages.js
  • git diff --check

GitHub checks and Greptile have restarted on the new head; no Frank action is needed.

@franksong2702

Copy link
Copy Markdown
Contributor Author

Base refresh pushed in 9585a553d.

  • Merged current origin/master through 17c2f2086 into Frank's PR branch; merges were clean with no manual conflict resolution.
  • The incoming base included ce048b0a5 for background-process restart recovery and Windows test-fixture symlink fallback, then changelog-only release commit 17c2f2086.
  • Incoming code/test files touched api/background_process.py, tests/conftest.py, tests/test_background_process_restart_recovery.py, tests/test_issue1880_profile_scoped_skills.py, and tests/test_issue6240_windows_skill_symlink_fallback.py; the final base commit was CHANGELOG.md only.

Verification:

  • ./scripts/test.sh tests/test_live_anchor_artifact_reference.py tests/test_background_process_restart_recovery.py tests/test_issue1880_profile_scoped_skills.py tests/test_issue6240_windows_skill_symlink_fallback.py -> 19 passed, 3 skipped
  • After the changelog-only release merge: ./scripts/test.sh tests/test_live_anchor_artifact_reference.py -> 8 passed
  • .venv/bin/python -m py_compile api/artifact_references.py api/streaming.py api/background_process.py api/process_event_utils.py tests/conftest.py
  • node --check static/messages.js
  • git diff --check

GitHub checks and Greptile have restarted on the new head; no Frank action is needed.

@franksong2702
franksong2702 force-pushed the franksong2702/live-stream-artifact-reference-derivation branch from c32a578 to 2064140 Compare July 31, 2026 13:33
@franksong2702

Copy link
Copy Markdown
Contributor Author

Rebuilt this branch from current master@dd7f6ac318 at head 2064140257.

  • Removed the bundled model catalog, profile switching, config cache, and atomic-write changes; the diff is now 11 files and only covers the Live-to-Final artifact ownership contract.
  • Kept the reviewer-required producer -> journal -> terminal settlement/reconnect/reload closure.
  • Closed the remaining proof gaps: bytes_written must be a non-negative integer, worker scenes carry server ownership authority, browser-posted artifact paths are revalidated against the session workspace, and the unrelated side_effects reattach expansion was removed.
  • Focused gate: 79 passed. Ruff diff, runtime ESLint, Python compilation, and git diff --check pass.

The PR body now reflects the rebuilt scope and current verification.

@nesquena-hermes nesquena-hermes left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Deep warm-up re-gate: changes requested

Certified head: 206414025777caa736cccc32c0fec098dc3fa0fb

The force-rebuild successfully removes the unrelated model/profile/config/atomic-write bundle, and the current artifact pipeline has strong path, owner, and budget checks. One deterministic authority gap remains in the core feature.

Blocking: a browser scene can invent an artifact that no file tool produced

_handle_session_anchor_scene() proves only that the parent assistant message has a trusted run/stream identity. It then merges the raw browser scene.artifacts list and marks the resulting record owner_authority="server". A browser artifact that repeats the trusted session/run/stream IDs therefore survives even when there is no matching server-derived artifact event, tool result, or file mutation.

I reproduced the full current-head path in the mandatory sandbox:

  1. settle a cancelled turn through the real server finalizer with artifact_events=[];
  2. POST a matching-owner client scene containing canonical-looking reports/never-written.md;
  3. save and reload the session;
  4. hydrate through _hydrate_anchor_activity_scenes().

The route returned 200, persisted the invented descriptor, and hydrated it again although the file did not exist and no canonical write_file/patch result had produced it. This does not need a traversal or owner-ID bypass; canonical path syntax is being mistaken for mutation authority.

Required fix

  1. Treat browser scene.artifacts as an untrusted projection. Retain an incoming row only when it exactly matches a server-derived artifact descriptor/event for that session/run/stream, including canonical path, source tool, tool_call_id, and preferably authoritative event ID/sequence. If the canonical server set is empty, reject or drop every incoming artifact.
  2. Do not promote a client-created artifact set to server authority merely because the parent message has trusted run/stream IDs. Preserve artifact authority only from server reconciliation/journal evidence.
  3. Validate the merged scene, and fail closed during read-side hydration for legacy/corrupt persisted artifact rows.
  4. Add a production-composed cancellation regression with zero canonical artifacts, a matching-owner invented browser row, save/reload, and hydration. Add controls proving an exact server-reconciled row survives once while wrong source_tool/tool_call_id variants cannot supplement or replace it.

Verification

  • Layer-1 threat scan: CLEAN
  • Mandatory no-network/no-secrets sandbox: test_live_anchor_artifact_reference.py 25 passed; test_anchor_scene_persistence.py 49 passed
  • Reviewer production-path diagnostic: 1 passed, confirming the unsafe accept → persist → reload behavior above
  • Exact head remained clean and unchanged after diagnostic cleanup

The visible artifact presentation still deserves the existing product/design sign-off, but this landed-evidence bypass is an objective data-authority defect and needs code/test rework first. No merge, approval, release, contributor-branch write, screenshot, or production action was performed.

@nesquena-hermes nesquena-hermes left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Deep warm-up re-gate: changes still requested

Certified head: 09d406e957009ba471c0dc182d3d4552f53fff0d

Thanks for the substantial response. The fresh browser-mint path from the prior review is now fixed: _handle_session_anchor_scene() substitutes only exact server journal/existing evidence, and the new authority key binds event ID, owner IDs, sequence, kind, path, source tool, and tool-call ID. The submitted accept → persist → hydrate regression now passes.

One deterministic lifecycle hole remains in the required legacy/corrupt-row fail-closed boundary.

Blocking: terminal reconciliation promotes an untrusted legacy artifact set to server authority

api/streaming.py::_reconcile_stream_artifacts_into_terminal_anchor_scene() reads the whole pre-existing scene at lines 2125-2127, merges every existing artifact with the current server-derived artifact at 2150-2164, then stamps the entire merged record artifact_authority="server" at 2168-2176. It never checks whether the existing record already had server artifact authority.

I reproduced the exact current-head path in the mandatory sandbox:

  1. seed the persisted pre-fix shape: matching server-owned message/scene, no artifact_authority, and browser-invented reports/never-written.md;
  2. deliver one legitimate server-derived patch event for reports/really-written.md;
  3. call the real terminal reconciler, save, reload, and run production hydration.

Both paths survived and rehydrated under the new server marker. One genuine mutation therefore launders an unrelated unknown browser artifact that has no durable file-tool evidence. This violates item 3 of the prior fix-spec: legacy/corrupt persisted artifact rows must fail closed.

Required fix

  1. Before merge_anchor_activity_scene(), sanitize the existing artifact set. If record["artifact_authority"] != "server", deep-copy the existing scene and clear its artifacts. If it is server-authoritative, retain only canonical owner/path-valid rows.
  2. Merge that filtered scene with the current call's server-derived artifacts. Set artifact_authority="server" only for the resulting server-evidenced set, never as a blanket promotion of an unmarked legacy scene.
  3. Add a production-composed regression: an unmarked pre-fix matching-owner record with an invented artifact plus one legitimate late patch/write_file event → real terminal reconcile → save/reload/hydrate. Assert only the legitimate artifact survives once, with exact event/tool/sequence/tool-call identity, and the invented row remains absent.

Gate evidence

  • Layer-1 threat scan: CLEAN.
  • Mandatory sandbox submitted targets: 102 passed / 0 failed.
  • Reviewer production-path legacy-laundering diagnostic: 1 passed, reproducing the unsafe promotion.
  • Positive real-journal control: 1 passed, proving legitimate server evidence still survives cold-cache-like lookup, POST, persistence, reload, and hydration.
  • Final post-diagnostic sandbox rerun: 102 passed / 0 failed; reviewer probes deleted; worktree clean.

The existing artifact-presentation design qualifier remains after this authority defect is fixed.

@nesquena-hermes nesquena-hermes added changes-requested Maintainer left detailed feedback requesting changes; PR is waiting on author to address and removed changes-requested Maintainer left detailed feedback requesting changes; PR is waiting on author to address labels Jul 31, 2026

@nesquena-hermes nesquena-hermes left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Watch re-gate: changes still requested

Certified head: dcaa34d23c5d4c3c840f45b82898aae7388faf04

Thanks for the follow-up. The new clear/filter branch is directionally correct, but the submitted legacy lifecycle regression never sends its invented row through that branch. The prior fail-closed acceptance item therefore is not yet proved, and the stale invented row remains durably persisted.

Blocking: the regression is false-green because it writes a different record key

_reconcile_stream_artifacts_into_terminal_anchor_scene() computes the assistant's SHA-256 message ref and reads only records.get(key) (api/streaming.py:2125-2129). The new test seeds the unmarked legacy scene under literal key index:1 (tests/test_live_anchor_artifact_reference.py:1323-1333). For this assistant message the digest is non-empty, so reconciliation reads an empty record, creates a second digest-keyed server record, and leaves the original index:1 row unchanged.

Session.save() serializes both records. On reload, _hydrate_anchor_activity_scenes() builds by_index with last-write-wins assignment (api/routes.py:4929-4943); the later digest-keyed record shadows the stale index:1 record. The test checks only the hydrated winner, not the durable record map. It therefore passes even though the invented legacy artifact is still saved.

The marked-record filter also calls retain_server_authoritative_artifact_events([raw_artifact], [raw_artifact], ...), using each persisted row as both authority and projection. That is self-authentication rather than reconciliation against independent server evidence. At minimum, marked rows need explicit, internally consistent session/run/stream/event/sequence identity before they are retained.

Required fix

  1. Resolve the target record by canonical message ref and, when it is absent, by one unambiguous legacy record with the same message_index and matching session/run/stream ownership. Remove the legacy key when writing the canonical record so only one durable record remains.
  2. Deep-copy that record, clear artifacts when artifact_authority != "server", and strictly validate any retained marked row's explicit owner fields, event/sequence identity, and canonical workspace path before merging the current server-derived events.
  3. Strengthen the production-composed regression with both canonical-keyed and index:1 legacy cases. After reconcile → save → reload, assert the durable record map contains exactly one canonical record, the invented path/event ID is absent from every persisted record, and the sole durable and hydrated artifact exactly matches the real event's session/run/stream/event/seq/path/source-tool/tool-call tuple. The test should fail if the clear/migration branch is removed.

Gate evidence

  • Layer-1 threat scan: CLEAN, score 0.
  • Mandatory no-network/no-secrets sandbox: focused terminal/legacy/authority slice 5 passed, 21 deselected; exact new test 1 passed; neighboring persistence-authority slice 3 passed, 48 deselected.
  • Those green results expose the oracle gap above; no full suite or screenshot was run in this watcher pass.

This is the same required legacy/corrupt-row fail-closed boundary from the prior review, so the PR remains in contributor court. No merge, approval, release, contributor-branch write, screenshot, or production action was performed.

Copy link
Copy Markdown
Contributor Author

Addressed the watch re-gate from dcaa34d23c on exact head af749fb940ac6abedecd22ba327e13ef90b13b37.

The three requested boundaries are now covered by 10abe158c3 plus af749fb940:

  1. Terminal reconciliation resolves the canonical message-ref record first and falls back only to one unambiguous legacy record whose message index and session/run/stream ownership match. Matching legacy keys are removed when the canonical record is written, including the canonical-plus-legacy duplicate case.
  2. The scene is deep-copied; artifacts are cleared when artifact_authority != "server"; marked persisted artifacts are retained only by reconciling them against the independently derived current server events, with owner/event/sequence validation and canonical workspace-path validation still fail-closed.
  3. The production-composed regression now covers both legacy-only and canonical-plus-multiple-legacy inputs. After reconcile -> save -> reload it asserts exactly one canonical durable record, no invented path/event survives anywhere, and the sole persisted and hydrated artifact exactly equals the real session/run/stream/event/seq/path/source-tool/tool-call tuple. Removing the migration/cleanup path makes this proof fail.

Hosted validation on this exact head is fully green: 23/23 checks, including browser smoke, docs, lint, all lifecycle scenarios, and the Python 3.11/3.12/3.13 matrix.

Requesting a fresh exact-head re-gate.

@nesquena-hermes

nesquena-hermes commented Aug 5, 2026

Copy link
Copy Markdown
Collaborator

Gate certification: FAIL

PR: #6207Live Stream: derive Anchor-owned file artifacts
Certified head: af749fb940ac6abedecd22ba327e13ef90b13b37
Integration base: origin/master at 320789ae596a3963d726d90f6c7f3bc86f7f2d6d
Tested integration commit: b84bccf06c72a111667f575b823f0ec5e5516e7a (tree-identical to the contributor head; tree e048a9032549f37d6ef6fa3de0095fcadf6c2a2b)

Evidence

  • Exact-head static threat scan: CLEAN, score 0. Exact tracked diff SHA-256: 9a13cfda77522b4af3dc3006fee2acbfe94ab5643ec293067056aa4badbd1313.
  • Complete standalone-clone sandbox suite: 13,841 passed, 87 skipped, 1 xfailed, 2 xpassed, 34 subtests passed. The remaining 17 failures and 2 errors were sandbox/native-topology nodes; all 19 reproduced on current master under the same sandbox.
  • Credential-free native topology rerun: 77 passed, 1 skipped. The sole skip was an unrelated ACL-capability test; every sandbox-failing node passed natively.
  • Focused artifact/Anchor persistence suites: 104 passed.
  • Ruff forward gate and git diff --check: clean.
  • Codex advisor: SAFE TO SHIP after 156 targeted tests, runtime ESLint, and state-space review.
  • Opus 4.8 crown-jewel review: APPROVE after 126 targeted tests.
  • Independent adversarial review: REQUEST CHANGES. Its workspace-authority finding reproduced in a reviewer-owned exact-diff sandbox probe.

Blocking finding: artifact authority survives workspace rebinding

Server artifact evidence is not bound to the workspace in which the mutation occurred:

  • api/artifact_references.py:362-369 persists a workspace-relative path and tool identity, but no immutable server-owned workspace identity.
  • api/streaming.py:2251-2259 marks the terminal scene and artifacts server-authoritative without recording their source workspace.
  • api/routes.py:4984-4992 later authenticates and validates persisted artifacts against the session's current workspace.
  • api/routes.py:14995-15022 permits that session workspace to be changed and saves existing Anchor records without invalidating or rebinding artifact authority.

Reproduction on the exact head:

  1. Create workspace A and workspace B, each containing a different report.md.
  2. In a session bound to A, reconcile a real server-owned write_file artifact for report.md into the terminal Anchor scene.
  3. Change the same session's workspace to B through the supported workspace-update state transition.
  4. Hydrate the persisted scene against B.
  5. The A-origin artifact remains present and now resolves to B's unrelated report.md.

The fail-closed probe expected no artifacts after rebinding, but received the original server-authoritative event while the two files contained artifact from A and unrelated file from B. This launders valid evidence from one workspace into another.

Required fix

  • Bind artifact authority to a canonical, server-owned workspace identity at derivation/reconciliation time. Do not accept a browser-supplied workspace claim as authority.
  • On session workspace changes, either invalidate/clear prior artifact authority or require the stored workspace identity to equal the current canonical workspace before persistence and hydration.
  • Apply the same invariant across live journal snapshots, terminal reconciliation, browser scene persistence, save/reload hydration, and legacy-record migration.
  • Add a production-composed regression for A → B rebinding with the same relative path but different file contents, including durable save/reload. It must fail closed without hiding unrelated non-artifact scene content.

Additional blocking finding: artifact verification is not input/scan bounded

The output list is bounded, but the authority pipeline still performs work over the complete raw input before and after normalization:

  • api/artifact_references.py:632-650 limits retained artifacts but scans every invalid or duplicate raw item before reaching that output limit.
  • api/routes.py:3640-3649 deep-copies the raw artifact array before reducing it.
  • api/routes.py:5061-5112 scans the original raw array again while retaining authority.
  • A request near the existing 20 MiB limit can encode millions of empty artifact objects. The isolated reducer took approximately 0.49 seconds for 500,000 invalid entries, before JSON parsing, deepcopy, and the second scan.
  • For valid entries, api/routes.py:5046,5095-5112 can invoke _run_journal_live_snapshot() while holding the per-session agent lock. That path globally searches journals and reads the selected JSONL without an event or byte bound (api/routes.py:3185-3193; api/run_journal.py:465-484,573-590). Repeated scene POSTs can therefore stall every operation for that session behind large journals.

Required remediation:

  • Reject or truncate over-limit raw artifact arrays before deepcopy or normalization.
  • Cap inspected entries and raw bytes independently of retained output count.
  • Replace the unbounded journal search/read with a bounded or indexed artifact-evidence lookup, and perform expensive evidence discovery outside the per-session lock before a short commit-time revalidation.
  • Add adversarial tests for large invalid arrays, duplicate-heavy arrays, large journals, repeated valid scene POSTs, and session responsiveness while evidence lookup is in progress.

Result: gate-fail — contributor action required, followed by exact-head warm-up and a full re-gate.

This certification does not merge, deploy, tag, close, or otherwise release the PR.

@franksong2702

Copy link
Copy Markdown
Contributor Author

Addressed the 2026-08-05 gate findings on exact head 267ba0bb45c56333ad73e99d4497d38388aa9e31.

Workspace authority

  • Server-resolved workspace roots now produce an opaque SHA-256 authority ID; absolute paths are not exposed.
  • The ID is carried through producer journal/SSE events, terminal reconciliation, Anchor record/scene identity, browser persistence, and hydration.
  • Journal and terminal evidence must carry the expected workspace authority. Missing or foreign incoming evidence fails closed instead of being rebound to the session's current workspace.
  • Existing legacy artifact events are retained only when both the server record and scene already carry the current workspace authority.
  • Durable A -> B regressions use different same-named report.md files and prove artifacts are dropped while non-artifact prose remains.

Bounded verification

  • Raw artifact inputs are rejected before deepcopy/normalization above independent 256-row / 128 KiB budgets; retained output remains independently capped at 64 rows / 32 KiB.
  • Artifact evidence lookup now uses the known session + run directly and reads at most 2 MiB / 4096 rows. Truncated journals preserve prose but contribute no artifact authority.
  • Anchor POST uses short capture and commit locks with journal discovery outside the per-session lock, then revalidates workspace, message ref/index, run, and stream before saving.
  • Added adversarial coverage for large invalid and duplicate-heavy arrays, bounded/truncated journals, repeated concurrent valid POSTs, browser workspace forgery, and foreign/missing workspace journal/terminal evidence.

Local verification:

  • Focused + neighboring artifact/Anchor/journal suites: 169 passed
  • python3 scripts/ruff_lint.py --diff HEAD^: 0 findings on added/modified lines
  • py_compile for all 8 touched Python files: exit 0
  • git diff HEAD^ --check: exit 0
  • Full repo run: 13,912 passed, 140 skipped, 1 xfailed, 2 xpassed, 8 failed; the 8 failures were outside the touched modules (atomic permission preservation, OpenAI TTS, and MiniMax environment detection), so they were not changed in this artifact-authority patch.

Hosted checks are running. Requesting a fresh exact-head warm-up and full re-gate after they settle.

@franksong2702

Copy link
Copy Markdown
Contributor Author

Refreshed PR #6207 onto current origin/master and resolved the streaming integration conflicts on exact head 7a74e09.

The resolution preserves both sides of the required invariant: current-session/writeback-owner/active-stream generation guards run before cancellation persistence, while the PR artifact helper and server-authoritative artifact reconciliation retain run_id and artifact_events. One integration regression in the Anchor persistence test was corrected to establish the master writeback-owner/current-session precondition.

Coordinator verification:

  • focused backend artifact/Anchor/journal/cancel matrix: 166 passed
  • frontend and neighboring matrix: 204 passed, 18 subtests passed
  • Node syntax, py_compile, and git diff --check against origin/master: exit 0
  • hosted GitHub Actions: all 15 Python shards, lint, docs, browser smoke, and three Live-to-Final jobs passed; Greptile is still pending at the time of this reply

Full local suite was not entirely green: 14,197 passed, 130 skipped, 1 xfailed, 2 xpassed, 8 failed. On targeted rerun, MiniMax passed; one macOS setgid permission assertion and six OpenAI TTS environment failures persisted. The affected implementations and tests are byte-identical to origin/master, so I did not mix unrelated fixes into this PR.

Conflict analysis assistance: Luna Max worker. I performed the merge resolution, diff review, regression correction, verification, commit, and push. Please re-review exact head 7a74e09 when the external check settles.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

gate-fail Gate found blocking issue(s); fix-spec in comment; awaiting fix/re-push size:L Large PR (>10 files or >250 LOC)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Live Stream: derive turn-owned artifact references from successful file mutations

2 participants