Skip to content

ci: bump actions/setup-python from 5 to 6 - #11

Closed
dependabot[bot] wants to merge 1 commit into
mainfrom
dependabot/github_actions/actions/setup-python-6
Closed

ci: bump actions/setup-python from 5 to 6#11
dependabot[bot] wants to merge 1 commit into
mainfrom
dependabot/github_actions/actions/setup-python-6

Conversation

@dependabot

@dependabot dependabot Bot commented on behalf of github Feb 2, 2026

Copy link
Copy Markdown

Bumps actions/setup-python from 5 to 6.

Release notes

Sourced from actions/setup-python's releases.

v6.0.0

What's Changed

Breaking Changes

Make sure your runner is on version v2.327.1 or later to ensure compatibility with this release. See Release Notes

Enhancements:

Bug fixes:

Dependency updates:

New Contributors

Full Changelog: actions/setup-python@v5...v6.0.0

v5.6.0

What's Changed

Full Changelog: actions/setup-python@v5...v5.6.0

v5.5.0

What's Changed

Enhancements:

Bug fixes:

... (truncated)

Commits
  • a309ff8 Bump urllib3 from 2.6.0 to 2.6.3 in /tests/data (#1264)
  • bfe8cc5 Upgrade @​actions dependencies to Node 24 compatible versions (#1259)
  • 4f41a90 Bump urllib3 from 2.5.0 to 2.6.0 in /tests/data (#1253)
  • 83679a8 Bump @​types/node from 24.1.0 to 24.9.1 and update macos-13 to macos-15-intel ...
  • bfc4944 Bump prettier from 3.5.3 to 3.6.2 (#1234)
  • 97aeb3e Bump requests from 2.32.2 to 2.32.4 in /tests/data (#1130)
  • 443da59 Bump actions/publish-action from 0.3.0 to 0.4.0 & Documentation update for pi...
  • cfd55ca graalpy: add graalpy early-access and windows builds (#880)
  • bba65e5 Bump typescript from 5.4.2 to 5.9.3 and update docs/advanced-usage.md (#1094)
  • 18566f8 Improve wording and "fix example" (remove 3.13) on testing against pre-releas...
  • Additional commits viewable in compare view

Dependabot compatibility score

Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


Dependabot commands and options

You can trigger Dependabot actions by commenting on this PR:

  • @dependabot rebase will rebase this PR
  • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
  • @dependabot merge will merge this PR after your CI passes on it
  • @dependabot squash and merge will squash and merge this PR after your CI passes on it
  • @dependabot cancel merge will cancel a previously requested merge and block automerging
  • @dependabot reopen will reopen this PR if it is closed
  • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
  • @dependabot show <dependency name> ignore conditions will show all of the ignore conditions of the specified dependency
  • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
  • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
  • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)

Bumps [actions/setup-python](https://github.com/actions/setup-python) from 5 to 6.
- [Release notes](https://github.com/actions/setup-python/releases)
- [Commits](actions/setup-python@v5...v6)

---
updated-dependencies:
- dependency-name: actions/setup-python
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
@dependabot dependabot Bot added dependencies Pull requests that update a dependency file github_actions Pull requests that update GitHub Actions code labels Feb 2, 2026
@jwbron jwbron closed this Feb 5, 2026
@dependabot @github

dependabot Bot commented on behalf of github Feb 5, 2026

Copy link
Copy Markdown
Author

OK, I won't notify you again about this release, but will get in touch when a new version is available. If you'd rather skip all updates until the next major or minor version, let me know by commenting @dependabot ignore this major version or @dependabot ignore this minor version. You can also ignore all major, minor, or patch releases for a dependency by adding an ignore condition with the desired update_types to your config file.

If you change your mind, just re-open this PR and I'll resolve any conflicts on it.

@dependabot
dependabot Bot deleted the dependabot/github_actions/actions/setup-python-6 branch February 5, 2026 02:07
james-in-a-box Bot added a commit that referenced this pull request Feb 11, 2026
Fixes critical and correctness issues raised in review:

1. Race condition in buffer rotation (Critical #1):
   - Use exclusive file lock during entire rotation operation
   - Write to temp file then atomically replace with os.replace()
   - Clean up temp file on error

2. Memory accumulation for streaming (Critical #2):
   - Cap collected chunks at 10MB to prevent resource exhaustion
   - Log when capture is truncated due to size limit

3. Missing error handling for failed API responses (Critical #3):
   - Capture 4xx/5xx responses with status code and error message
   - Pass status_code to capture function for proper handling

4. Missing input_tokens from message_start (Correctness #4):
   - Extract input_tokens, cache_read_input_tokens from message_start
   - message_delta only contains output_tokens per SSE spec

5. Error events not handled in SSE parsing (Correctness #4):
   - Handle 'error' event type and capture as error content block
   - Add input_parse_error flag when tool_use JSON fails to parse

6. Unsafe path construction (Correctness #6):
   - Validate container_id against path traversal characters
   - Verify resolved path is within buffer directory

Minor fixes:
- Move `import time` to module level (Minor #10)
- Set buffer directory permissions to 0o700 (Minor #11)

Authored-by: egg
jwbron pushed a commit that referenced this pull request Feb 11, 2026
…pt capture (#517)

* Initialize SDLC contract for issue #509

* Draft analysis for issue #509: checkpoint migration

* Update refine review state (cycle 1)

* Approve and advance to plan phase for issue #509

* Draft plan for issue #509: per-commit checkpoints and API proxy capture

* Update plan review state (cycle 1)

* Approve and advance to implement phase for issue #509

* Populate contract tasks from plan for issue #509

* Implement per-commit checkpoint granularity (Phase 1)

Add support for creating one checkpoint per commit instead of one per push:

- Add get_commits_in_push() helper to enumerate commits between old/new SHAs
- Add capture_and_store_checkpoints_for_push() for multi-commit checkpoint creation
- Modify gateway push handler to get remote ref before push and iterate commits
- Each checkpoint now has push_sha pointing to the tip commit for traceability
- Graceful fallback: if rev-list fails, creates single checkpoint for tip commit

This is Phase 1 of issue #509 (per-commit checkpoints + API proxy capture).
Transcript source is still Claude Code JSONL (to be migrated in Phase 3).

Authored-by: egg

* Implement API proxy transcript capture (Phase 2)

Add instrumentation to the Anthropic API proxy to capture request/response
pairs for checkpoint creation:

- New TranscriptBuffer class manages per-session buffer files in /tmp/egg-transcripts/
- Fixed 10MB buffer rotation drops oldest entries when size limit exceeded
- Non-streaming responses captured with full content and usage
- Streaming SSE responses reassembled to extract content blocks
- Buffer entry schema documented with timestamps, model, messages, tools, usage
- Thread-safe file writes with file locking
- Global buffer cache for efficient access by container ID

This is Phase 2 of issue #509 (per-commit checkpoints + API proxy capture).
Phase 3 will migrate checkpoint extraction to use this buffer instead of
Claude Code JSONL files.

Authored-by: egg

* Migrate transcript source to API proxy buffer (Phase 3)

Replace Claude Code JSONL extraction with API proxy buffer reading:

- Add extract_transcript_from_proxy_buffer() and related extraction functions
- Update CheckpointHandler.capture_checkpoint() to use proxy buffer instead of JSONL
- Remove CLAUDE_PROJECTS_DIR constant (no longer needed)
- Maintain same return types for backward compatibility

The proxy buffer provides a stable API-based source for transcripts,
eliminating dependency on Claude Code's internal file format which
can change without notice.

This is Phase 3 of issue #509. Phase 4 will clean up deprecated JSONL code
and add buffer cleanup on session end.

Authored-by: egg

* Cleanup and documentation for proxy buffer architecture (Phase 4)

- Remove all Claude Code JSONL-specific code from transcript_extractor.py
  (file now only contains proxy buffer extraction functions)
- Add buffer cleanup on session end in session_manager.py
- Update CLI help text to describe per-commit checkpoint behavior
- Add architecture documentation in checkpoint_handler.py explaining
  the transcript flow from API proxy to checkpoint storage

Authored-by: egg

* Update autofix attempts for issue #509

* Address review feedback on PR #517 transcript capture

Fixes critical and correctness issues raised in review:

1. Race condition in buffer rotation (Critical #1):
   - Use exclusive file lock during entire rotation operation
   - Write to temp file then atomically replace with os.replace()
   - Clean up temp file on error

2. Memory accumulation for streaming (Critical #2):
   - Cap collected chunks at 10MB to prevent resource exhaustion
   - Log when capture is truncated due to size limit

3. Missing error handling for failed API responses (Critical #3):
   - Capture 4xx/5xx responses with status code and error message
   - Pass status_code to capture function for proper handling

4. Missing input_tokens from message_start (Correctness #4):
   - Extract input_tokens, cache_read_input_tokens from message_start
   - message_delta only contains output_tokens per SSE spec

5. Error events not handled in SSE parsing (Correctness #4):
   - Handle 'error' event type and capture as error content block
   - Add input_parse_error flag when tool_use JSON fails to parse

6. Unsafe path construction (Correctness #6):
   - Validate container_id against path traversal characters
   - Verify resolved path is within buffer directory

Minor fixes:
- Move `import time` to module level (Minor #10)
- Set buffer directory permissions to 0o700 (Minor #11)

Authored-by: egg

* Address re-review feedback: add raw_partial_input and doc comments

- Include truncated raw_partial_input in tool_use blocks when JSON parsing
  fails, for debugging incomplete streaming responses (re-review issue #1)
- Add docstring notes documenting:
  - Tool result matching order-dependency (original issue #5)
  - Force push checkpoint behavior (original issue #7)
  - Shared transcript for multi-commit pushes (original issue #8)
  - container_id fallback from filename (original issue #12)
- Fix import sorting in gateway.py (ruff auto-fix)

Authored-by: egg

* Address minor review observations: add constant and logging

- Add RAW_INPUT_TRUNCATE_SIZE constant for the 1000 char truncation
  threshold used when preserving raw tool input on parse failure
- Add warning log in transcript_extractor when extracting tool calls
  with input_parse_error flag, surfacing streaming parse failures
  during checkpoint extraction

Authored-by: egg

* Add test coverage for input_parse_error handling path

Adds tests for the input_parse_error and raw_partial_input handling
that was added for incomplete streaming JSON responses. This addresses
the non-blocking observation from the PR review to ensure the
defensive code path is documented through tests and protected from
regressions.

- TestParseSSEResponse: Tests that incomplete tool_use JSON sets
  input_parse_error flag and preserves truncated raw_partial_input
- TestExtractToolCallsFromProxyBuffer: Tests that extraction logs
  a warning when input_parse_error is present and truncates the
  raw input preview appropriately

Authored-by: egg

---------

Co-authored-by: james-in-a-box[bot] <2365503+james-in-a-box[bot]@users.noreply.github.com>
Co-authored-by: james-in-a-box[bot] <246424927+james-in-a-box[bot]@users.noreply.github.com>
james-in-a-box Bot added a commit that referenced this pull request Feb 12, 2026
Critical fix (AC-28):
- Refactor run_interactive() and run_exec() to use subprocess.run()
  instead of os.execvpe() so entrypoint regains control after process
  exit and can signal completion to orchestrator

Code quality fixes:
- Use OrchestratorClient in entrypoint instead of raw urllib (#2)
- Add thread-safe singleton pattern with double-checked locking (#3)
- Add progress_percent validation (0-100) to ProgressData (#4)
- Standardize health check timeout to 5s, signal ops to 10s (#5)
- Preserve response body before JSON parsing in error handling (#7)
- Add warning log when using fallback constants (#9)
- Move ENV_AGENT_ROLE import to module level in detection.py (#10)
- Fix docstring mismatch in gateway _check_orchestrator_connectivity (#11)
- Export get_orchestrator_client from package __init__.py

Authored-by: egg
jwbron added a commit that referenced this pull request Feb 12, 2026
#556)

* Initialize SDLC contract for issue #544

* Draft analysis for issue #544

Analyze the five remaining orchestrator integration items:
- AC-24: Gateway health reports orchestrator connectivity
- AC-27: Typed sandbox-to-orchestrator API client
- AC-28: Sandbox orchestrator mode detection and completion reporting
- AC-29: shared/egg_orchestrator/ shared package
- AC-33: Orchestrator architecture documentation

Recommends hybrid approach following existing patterns.
Includes HITL decisions for completion signaling method and
shared types scope.

Authored-by: egg

* Update refine review state (cycle 1)

* Approve and advance to plan phase for issue #544

* Draft plan for issue #544: orchestrator integration items

* Update plan review state (cycle 1)

* Approve and advance to implement phase for issue #544

* Populate contract tasks from plan for issue #544

* Add shared/egg_orchestrator/ package (AC-29)

Create shared package for orchestrator types and utilities used by both
gateway and sandbox containers. This provides:

- OrchestratorClient: Typed client for sandbox-to-orchestrator communication
- Orchestrator mode detection utilities (is_orchestrator_mode)
- Deployment mode enum (LOCAL, REMOTE_SINGLE, DISTRIBUTED)
- Signal types for completion reporting (complete, progress, error, heartbeat)
- Constants and configuration for orchestrator connectivity

The package is designed to be imported by both containers without creating
circular dependencies. It uses only standard library for HTTP communication
to avoid adding dependencies.

Authored-by: egg

* Add orchestrator connectivity to gateway health endpoint (AC-24)

The /api/v1/health endpoint now reports orchestrator connectivity status
when an orchestrator URL is configured via EGG_ORCHESTRATOR_URL. The
response includes:

- orchestrator.configured: Whether orchestrator URL is set
- orchestrator.reachable: Whether the orchestrator responded to health check
- orchestrator.status: Orchestrator health status if reachable
- orchestrator.error: Error message if unreachable

This enables monitoring tools to verify the full gateway-orchestrator
communication path during distributed deployments.

Authored-by: egg

* Add sandbox orchestrator mode detection and completion reporting (AC-28)

The sandbox entrypoint now detects when running in orchestrator mode
(vs interactive/local) and signals completion/error back to the
orchestrator on container exit. Detection is based on:

- EGG_ORCHESTRATOR_MODE environment variable (explicit)
- EGG_PIPELINE_ID environment variable (implicit)
- EGG_ORCHESTRATOR_URL environment variable (implicit)

On exit, the sandbox sends a signal to the orchestrator's signal API:
- "complete" signal for successful exit (exit code 0)
- "error" signal for failed exit with error message

This enables the orchestrator to track sandbox lifecycle without polling
container status, and to coordinate multi-agent workflows.

Authored-by: egg

* Add orchestrator architecture documentation (AC-33)

Document the three deployment modes and how components interact:

1. Local mode: Interactive sandbox with gateway sidecar
2. Remote-single mode: Orchestrator spawns single managed sandbox
3. Distributed mode: Orchestrator coordinates multiple agent sandboxes

Includes:
- Network architecture diagrams (ASCII)
- Component interaction details
- Signal flow for sandbox lifecycle
- Environment variable reference
- Shared package documentation

Also updates architecture README to reference the new orchestrator doc
and adds egg_orchestrator to the components table.

Authored-by: egg

* Update autofix attempts for issue #544

* Address review feedback on orchestrator integration PR

Critical fix (AC-28):
- Refactor run_interactive() and run_exec() to use subprocess.run()
  instead of os.execvpe() so entrypoint regains control after process
  exit and can signal completion to orchestrator

Code quality fixes:
- Use OrchestratorClient in entrypoint instead of raw urllib (#2)
- Add thread-safe singleton pattern with double-checked locking (#3)
- Add progress_percent validation (0-100) to ProgressData (#4)
- Standardize health check timeout to 5s, signal ops to 10s (#5)
- Preserve response body before JSON parsing in error handling (#7)
- Add warning log when using fallback constants (#9)
- Move ENV_AGENT_ROLE import to module level in detection.py (#10)
- Fix docstring mismatch in gateway _check_orchestrator_connectivity (#11)
- Export get_orchestrator_client from package __init__.py

Authored-by: egg

* Address review feedback on orchestrator integration PR

Key changes addressing reviewer feedback:

1. Signal handler logic (#5): Track subprocess completion state to report
   correct exit codes. If SIGTERM arrives before subprocess completes,
   report interrupted status (128+signum) instead of always success (0).

2. TTY handling (#4): Add explicit stdin/stdout/stderr to subprocess.run()
   calls to ensure consistent terminal behavior after the switch from
   os.execvpe() to subprocess.run().

3. Security: Unknown phase fail-closed (#1): Change phase_filter to block
   files for unknown phases instead of allowing by default. This prevents
   bypass via invalid phase strings.

4. Security: Path escape validation (#2): Add validation in _normalize_path
   to block paths that escape the repository (e.g., ../../../etc/passwd).

5. py.typed marker file (#1): Add empty py.typed file for PEP 561 type
   checking support in egg_orchestrator package.

6. Test coverage: Add comprehensive tests for:
   - egg_orchestrator types, client, detection
   - Entrypoint orchestrator mode and subprocess handling
   - Gateway health orchestrator connectivity
   - Phase filter unknown phase blocking and path escape validation

Authored-by: egg

* Address contract verification feedback for AC-22, AC-23, AC-25, AC-13, AC-20

Fix acceptance criteria verification issues:
- AC-22: Change orchestrator health check timeout from 5s to 2s as specified
- AC-23: Include URL field in orchestrator health response when configured
- AC-25: Add test for orchestrator unreachable case (connection failure)
- AC-13: Add HTTP response tests for signal methods with mocked responses
- AC-20: Add tests verifying signals are sent on normal exit and error exit

Authored-by: egg

* Add url field verification to orchestrator health test

The test_health_check_orchestrator_reachable test was mocking
_check_orchestrator_connectivity without including the url field
that the actual implementation returns. Updated the mock and
added an assertion to verify the url field is present.

Authored-by: egg

---------

Co-authored-by: james-in-a-box[bot] <2365503+james-in-a-box[bot]@users.noreply.github.com>
Co-authored-by: james-in-a-box[bot] <246424927+james-in-a-box[bot]@users.noreply.github.com>
Co-authored-by: jwbron <8340608+jwbron@users.noreply.github.com>
james-in-a-box Bot pushed a commit that referenced this pull request Mar 17, 2026
1. Wire check_anchor_write_permission into gateway push validation path.
   Add agent_anchor_id to Session dataclass, session creation API, gateway
   client, and container spawner. Anchor file writes are now enforced at
   the gateway level (not just defined in phase_filter.py).

2. Add agent_id input validation with regex (^[a-zA-Z0-9_-]+$) in both
   the API routes and the loader's _anchor_path to prevent path traversal
   and Redis key injection.

3. Validate agent_id consistency between URL parameter and request body
   in create_or_update_anchor endpoint.

4. Remove unbounded Redis scan (_get_pipeline_id_for_agent). GET and
   DELETE endpoints now require pipeline_id as a mandatory query parameter.
   Update CLI to pass EGG_PIPELINE_ID for cross-agent reads.

5. Fix test helper _make_anchor_file to create schema-valid anchor data
   (team as array, task as object, _meta with created_at, no non-existent
   fields).

6. No authentication added to anchor API routes — the orchestrator is an
   internal service on the Docker network with no auth on any routes. This
   is by design, not an oversight.

Also addresses non-blocking suggestions:
- Return 201 for new anchor creation, 200 for updates (#7)
- Set 24h default TTL on anchor Redis keys, refreshed on each write (#8)
- Copy decision dicts before adding from_agent to avoid in-place mutation (#10)
- Fix overly broad exception handler in loader.py (#11)
- Add new tests for agent_id validation, body mismatch, 201/200 status codes,
  and pipeline_id requirement
jwbron added a commit that referenced this pull request Mar 17, 2026
* Add analysis for agent anchor mechanism (#1032)

* Add refine review verdict for issue 1032

* Add agent-design review for issue 1032 refine phase

* Address reviewer feedback: add specific line references for gateway and spawner integration

* Update agent-design review for issue 1032 refine phase v2

* Update refine review verdict for issue 1032 - approved after revision

* Add risk assessment for agent anchor mechanism (#1032)

* Add implementation plan for agent anchor mechanism (#1032)

* Add architect analysis for issue 1032 plan phase

* Add plan review verdict for issue 1032 - approved

* Add documentation for agent anchor mechanism (#1032)

Add comprehensive documentation for the agent anchor post-compaction state
recovery feature:

- shared/egg_anchor/README.md: Package reference with Quick Start, models,
  functions, architecture, and integration points
- docs/guides/anchor-recovery.md: Recovery protocol guide covering the
  full clear-and-reload workflow, BRC consensus recovery, and troubleshooting
- docs/reference/orchestrator-cli.md: Added egg-orch anchor subcommands
  and AGENT_ANCHOR_ID env var
- docs/index.md: Added anchor recovery guide and task-specific lookup entry
- docs/development/STRUCTURE.md: Added egg_anchor package and routes/anchors.py
- orchestrator/README.md: Added anchor API endpoints section
- shared/README.md: Added egg_anchor package description
- docs/guides/concurrent-execution.md: Added anchor section for BRC recovery
- sandbox/.claude/rules: Updated orchestrator.md with anchor commands,
  README.md with anchor-recovery.md entry

* Add agent anchor mechanism for post-compaction state recovery

Implement persistent agent anchors that capture working state (task
progress, cross-agent decisions, BRC consensus, key context) at natural
milestones. When an agent's context window fills, it can be fully cleared
and reloaded from the anchor file for deterministic recovery.

Phase 1: JSON Schema, constants, shared egg_anchor library (Pydantic
models, atomic file I/O, schema validator), egg-orch anchor CLI.
Phase 2: REST API endpoints (Flask Blueprint), Redis storage for
cross-agent access, team anchor generation.
Phase 3: Gateway phase filter allows anchor writes in all phases,
session-scoped enforcement, container spawner AGENT_ANCHOR_ID env var,
consensus wrapper anchor loading, sandbox recovery rules.
Phase 4: Checkpoint integration, lifecycle management, GC.

153 new tests pass covering all phases.

Issue: #1032

* Add comprehensive tests for agent anchor mechanism (#1032)

181 tests covering: Pydantic models (28), file I/O and API sync (18),
schema validation (24), size budget and validator (26), gateway phase
filter permissions (11), orchestrator routes (11), consensus wrapper
anchor recovery (7), container spawner env vars (4), lifecycle events
(9), CLI placeholders (4), constants (12), checkpoint integration (3),
and JSON Schema conformance (24). Includes gap tests for concurrent
access, boundary values, path normalization, and cross-agent write
rejection. All tests pass with clean ruff lint.

* Display anchor data in egg-checkpoint show output

Address reviewer_contract NACK on task-4-1: checkpoint_cli.py now displays
agent anchor information (agent_id, role, status, task, progress, BRC state,
decisions, files modified, errors) when anchors are present in checkpoint data.

* Fix checks: apply automated formatting fixes

* Fix mypy errors in egg_anchor: add type annotations and overrides

* Fix mypy errors in egg_anchor test_models: add type annotations

* Address review feedback: fix 6 blocking issues in anchor mechanism

1. Wire check_anchor_write_permission into gateway push validation path.
   Add agent_anchor_id to Session dataclass, session creation API, gateway
   client, and container spawner. Anchor file writes are now enforced at
   the gateway level (not just defined in phase_filter.py).

2. Add agent_id input validation with regex (^[a-zA-Z0-9_-]+$) in both
   the API routes and the loader's _anchor_path to prevent path traversal
   and Redis key injection.

3. Validate agent_id consistency between URL parameter and request body
   in create_or_update_anchor endpoint.

4. Remove unbounded Redis scan (_get_pipeline_id_for_agent). GET and
   DELETE endpoints now require pipeline_id as a mandatory query parameter.
   Update CLI to pass EGG_PIPELINE_ID for cross-agent reads.

5. Fix test helper _make_anchor_file to create schema-valid anchor data
   (team as array, task as object, _meta with created_at, no non-existent
   fields).

6. No authentication added to anchor API routes — the orchestrator is an
   internal service on the Docker network with no auth on any routes. This
   is by design, not an oversight.

Also addresses non-blocking suggestions:
- Return 201 for new anchor creation, 200 for updates (#7)
- Set 24h default TTL on anchor Redis keys, refreshed on each write (#8)
- Copy decision dicts before adding from_agent to avoid in-place mutation (#10)
- Fix overly broad exception handler in loader.py (#11)
- Add new tests for agent_id validation, body mismatch, 201/200 status codes,
  and pipeline_id requirement

* Address non-blocking review suggestions on anchor mechanism

- Remove redundant `import re` in gateway.py session_create (already
  imported at module level)
- Add 128-char length limit to loader.py _validate_agent_id for
  defense-in-depth (matches API route validation)
- Add test_delete_without_pipeline_id_returns_400 negative test
- Add gateway integration tests for anchor push validation (mismatched
  anchor write denied, own anchor write allowed)

* Add gateway integration test for None anchor_id with anchor file write

* Simplify anchor push tests: use = None and parametrize denial cases

Addresses non-blocking review suggestions:
- Replace `del mock_session.agent_anchor_id` with direct `= None`
  assignment for clarity and Python version portability
- Consolidate two anchor denial tests into a single parametrized
  test to eliminate ~35 lines of duplication

---------

Co-authored-by: egg <egg@localhost>
Co-authored-by: james-in-a-box[bot] <246424927+james-in-a-box[bot]@users.noreply.github.com>
Co-authored-by: egg-reviewer[bot] <261018737+egg-reviewer[bot]@users.noreply.github.com>
james-in-a-box Bot pushed a commit that referenced this pull request Apr 23, 2026
…EADME

Adds a brief note on the /v1/messages endpoint in gateway/README.md that
surfaces the new upstream stream-reset resilience behavior (#1907) and
points readers to the full design rationale in the credential-injection
architecture doc. Also captures it as design decision #11 in the
gateway README so it is discoverable alongside the other enforcement
mechanisms.

The detailed design (pre-stream retry vs. mid-stream synthetic SSE error
frame, bounds, why no full resumption, scope relative to #1883/#1873)
continues to live in docs/architecture/credential-injection.md; this
commit only adds the discoverability breadcrumb from the gateway README.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
jwbron pushed a commit that referenced this pull request Apr 23, 2026
…eam reset (#1913)

* Initialize SDLC contract for issue #1907

* docs: document gateway upstream stream-reset resilience

Describe the pre-stream retry and mid-stream synthetic SSE error-event
behavior added to proxy_anthropic_messages() for issue #1907. Explains
why mid-stream retry is unsafe (no Anthropic resume tokens) and how the
fix differs from #1883 (gateway pod restart) and #1873 (turn-1 retry).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* Fix #1907: make gateway /v1/messages resilient to upstream TCP resets

Anthropic's edge resets long-running SSE connections routinely (load-balancer
rebalance, idle timeout, middlebox). When that happens mid-stream, the gateway
was propagating httpcore.ReadError as a bare socket close, which the downstream
Claude SDK surfaced as a fatal "socket connection was closed unexpectedly" —
killing the agent and losing all in-flight work (#1901 architect lost 282s /
32 turns / $1.33 of context-building this way).

Two complementary fixes inside proxy_anthropic_messages():

- (A) Pre-stream retry. Pre-fetch the first chunk before returning the Flask
  Response. If client.send() or that first iter_bytes() call raises ReadError
  or RemoteProtocolError before any byte has flowed downstream, close the
  failed upstream and reissue the request once. Transparent to the SDK.
  Covers connection-pool staleness and very-early resets.

- (B) Mid-stream synthetic error frame. If the reset arrives after a chunk
  has already been yielded downstream, emit a well-formed Anthropic-style
  'event: error' SSE frame and close the stream cleanly. The SDK treats that
  as a clean API error instead of a truncated socket, and the _SSEAccumulator
  records it in the captured transcript so operators can still see the
  failed turn. Full resumption is not attempted — Anthropic's API has no
  resume tokens.

Distinct from #1883 (gateway pod restart); this covers the gateway-healthy /
upstream-unhealthy case.

Test additions for this change live in
.egg-state/agent-outputs/coder-test-additions-issue-1907.patch and are handed
off to the tester role (tests/ is outside coder's file boundary).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* Handoff: test additions for #1907 gateway stream-reset resilience

Three new tests for TestStreamingResponse in tests/gateway/test_anthropic_proxy.py,
ready for the tester role to apply (tests/ is outside coder's file boundary).

Apply with: git apply .egg-state/agent-outputs/coder-test-additions-issue-1907.patch

Covers:
- (a) client.send() raises ReadError once then retry succeeds
- (b) first iter_bytes() raises ReadError then retry re-primes and succeeds
- (c) mid-stream RemoteProtocolError after one chunk -> synthetic SSE error
  frame appended, stream closes cleanly, upstream.close() still runs

All three verified locally against commit dc5058a: `pytest
tests/gateway/test_anthropic_proxy.py -v` -> 49 passed. Tester is free to
adjust phrasing / add cases; intent is to lock in the contract acceptance
criteria for task-1-3.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* Tests: gateway upstream stream-reset resilience (#1907)

Extend tests/gateway/test_anthropic_proxy.py::TestStreamingResponse with
coverage for the pre-stream retry and mid-stream synthetic error-frame
paths added to proxy_anthropic_messages() in commit dc5058a.

New tests (task-1-3):

- test_streaming_send_reset_retries_once
  client.send() raises httpx.ReadError once, retry succeeds, downstream
  sees a clean 200 SSE response with no synthetic error frame. Verifies
  send() called exactly twice.

- test_streaming_first_chunk_reset_retries_once
  First iter_bytes() pull raises ReadError, gateway re-primes with a
  fresh upstream, stream completes normally. Verifies the failed
  upstream is closed before the retry so the httpx connection pool
  doesn't leak a half-open connection.

- test_streaming_midstream_reset_yields_synthetic_error_frame
  iter_bytes() raises httpx.RemoteProtocolError after one chunk has
  already been yielded. Verifies the downstream body is: original
  chunk + well-formed SSE `event: error` frame with Anthropic-style
  payload, that the body ends with the SSE terminator, that no retry
  is attempted, that upstream.close() still runs, and parses the
  synthetic frame's JSON to catch any malformed output.

Plus one extra defense-in-depth case:

- test_streaming_send_reset_retry_exhausted_returns_502
  Both attempts raise — bounded 1x retry, caller gets 502 and the
  gateway does not loop or leak.

All tests use a small helper _iter_then_raise() that wraps an iterator
so it raises after N yielded chunks, matching the contract's
"helper to wrap an iterator so it raises after N yielded chunks" clause.

pytest tests/gateway/test_anthropic_proxy.py -> 50 passed
ruff check + ruff format --check clean

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* docs: cross-reference gateway upstream stream resilience in gateway README

Adds a brief note on the /v1/messages endpoint in gateway/README.md that
surfaces the new upstream stream-reset resilience behavior (#1907) and
points readers to the full design rationale in the credential-injection
architecture doc. Also captures it as design decision #11 in the
gateway README so it is discoverable alongside the other enforcement
mechanisms.

The detailed design (pre-stream retry vs. mid-stream synthetic SSE error
frame, bounds, why no full resumption, scope relative to #1883/#1873)
continues to live in docs/architecture/credential-injection.md; this
commit only adds the discoverability breadcrumb from the gateway README.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* Persist statefiles after implement phase

* Remove ephemeral agent-output handoff artifacts (#1731)

* Address review feedback: resource leak fix, doc wording, cleanup

---------

Co-authored-by: egg-orchestrator <egg@localhost>
Co-authored-by: egg <egg@example.com>
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
Co-authored-by: james-in-a-box[bot] <246424927+james-in-a-box[bot]@users.noreply.github.com>
james-in-a-box Bot pushed a commit that referenced this pull request May 11, 2026
…lockers

Reviewer_plan NACKed the v1 plan with one blocking item (single-OR
JQL fails on team-managed Jira projects) plus 20 non-blocking flags
ranked by impact. This revision lands the blocker plus the 10
highest-impact non-blockers in one re-propose.

Blocker:
- TASK-1-3 + TASK-1-12: replace the single-OR JQL
  `parent = <K> OR "Epic Link" = <K>` with two separate queries
  (`parent = "<K>"` and `"Epic Link" = "<K>"`) and merge results,
  tolerating per-query HTTP 400 (architect ad-9 / risk_analyst R4).
  Single-OR fails on team-managed projects that lack the
  "Epic Link" custom field; auto-detection silently downgrades to
  fresh-path and the sweep returns empty. Exports the helper
  `search_epic_children` so TASK-1-12 reuses it.

Top non-blocking (reviewer-flagged as most impactful):
- #1 In-flight gate trust-boundary trade-off: add explicit
  acknowledgement that gateway-side enforcement is deferred and
  v1 relies on agent-side gating + apply-time re-check by
  TASK-1-13.
- #5 APPLY_EPIC role registration: expand TASK-1-10 to enumerate
  all FIVE registration steps (AgentRole, AgentRoleDefinition,
  get_roles_for_phase, file-restrictions patterns, spawner
  branch).
- #6 epic_apply persistence MCP surface: add
  `mcp__sdlc__update_epic_apply` MCP tool to TASK-1-7 so the
  sandbox-side agent can persist artifact updates.
- #7 Concurrent-edit guard: TASK-1-10 now fetches the current
  epic Description, sha256s it, and registers a divergence HITL
  on mismatch; TASK-1-9 records the baseline sha256;
  TASK-1-7 adds `refine_description_sha256` to the schema.

Additional non-blockers folded in:
- #2: jira_effective_mode added to primitives table.
- #3: TASK-1-5 introduces `shared/egg_jira_credentials.py` shared
  module to eliminate the orchestrator → gateway coupling.
- #8: TASK-1-11 commits to extending `parse_plan` (not
  pass-through).
- #9: TASK-1-5/TASK-1-14 add already-in-state idempotent
  short-circuit for Won't-Do transitions.
- #10: TASK-1-15 introduces `Pipeline.jira_parent_epic_key` so PR
  phase doesn't need an extra Jira call.
- #11: TASK-1-16 adds `PipelinePhase.PLAN_STOPPED` documented
  terminal phase + updates overseer monitor short-circuit.
- #14: TASK-1-11 requires `wont_do_reason` per node + ⚠ warning
  rendering in the plan draft (R6).
- #15: TASK-1-5 gates the orchestrator-direct cred surface behind
  `EGG_ENABLE_ORCH_JIRA_TRANSITIONS` (default off — R1).
- #16: TASK-1-7 schema gains `version`, `idempotency_seed`,
  per-edit `summary_hash` + `applied_at`, `wont_do_reason`,
  signal_source as a list (R10).
- #19: TASK-1-19 drops orchestrator-cli.md, adds
  submit-task-mcp.md.
- #13: TASK-1-18 adds the lint regression test
  `test_no_outbound_jira_writes.py` (R7).
- #12: TASK-1-12 introduces a reverse-index
  `.egg-state/jira-child-pipeline-index.json` to bound the sweep
  to O(K) (R3 performance mitigation).
- #20: New "Risk-analyst items addressed" section summarises how
  R1/R2/R6/R7/R10/R12 are resolved in-plan (no fresh HITLs).

Plan still parses cleanly: 1 slice, 19 tasks, 0 warnings, 0
role-alignment errors.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
james-in-a-box Bot pushed a commit that referenced this pull request May 12, 2026
…K v3

Addresses the BLOCKING holistic findings (Pass 1+2+3+4):

* **#1 — `submit_task --mode` is now consumed end-to-end.** The
  `create_pipeline()` route in `orchestrator/routes/pipelines.py` reads
  `data["jira_ticket"]` and `data["jira_epic_mode"]` (the latter set
  by `submit_task`), runs the detection probe, and persists
  `jira_epic_key` / `jira_effective_mode` / `jira_parent_epic_key` on
  the Pipeline via the StateStore. `mcp_tools.py` now forwards
  `jira_ticket` explicitly so the route doesn't have to parse it back
  out of `pipeline_id`.
* **#2 — `Pipeline.jira_epic_key` / `jira_effective_mode` /
  `jira_parent_epic_key` are now written.**
  `StateStore.create_pipeline()` accepts and forwards all three.
* **#3 + #4 — `apply_epic` is now opted into the refine and plan
  phase rosters when `pipeline.jira_epic_key` is set.**
  `get_roles_for_phase()` grows an `is_epic_pipeline` parameter
  gated on the field's presence; the orchestrator's role-resolution
  site at `routes/pipelines.py` passes the flag. Sandbox env now
  exports `EGG_JIRA_EPIC_KEY`, `EGG_JIRA_EFFECTIVE_MODE`,
  `EGG_JIRA_PARENT_EPIC_KEY`, and the resolved `EGG_JIRA_HIERARCHY_FIELD`
  (looked up via `resolve_hierarchy_field`; a missing mapping leaves
  the env empty and the apply step surfaces a HITL gate).
* **#5 — `PipelinePhase.PLAN_STOPPED` enum value added** to
  `shared/egg_contracts/models.py`. Terminal-without-PR signal for
  the Stop-after-plan plan-gate fork.
* **#11 — `detect_jira_issuetype` exception handling narrowed.**
  Catches `ConnectionError` / `TimeoutError` / `OSError` and
  HTTP-failure exceptions (those carrying `status_code`) but lets
  programming errors propagate.
* **#12 — `_run_jql` 400 tolerance is now `tolerate_400` keyword.**
  Only the `"Epic Link"` query opts in; `parent =` 400s surface
  to the caller so malformed-JQL / permission errors aren't
  silently treated as empty children.
* **#13 — `search_epic_children` `require_hierarchy_mapping=True`**
  re-raises `JiraHierarchyUnmappedError` so callers (the apply step,
  per decision-2) can surface a HITL gate rather than silently
  running both queries.

For **#6** (the planned `mcp__sdlc__update_epic_apply` and
`mcp__sdlc__register_in_flight_gate` MCP tools) the agent prompts
in `orchestrator/agent_prompts/apply_epic.py` are reframed to use
the existing `mcp__sdlc__register_open_question` for HITL gates and
a file-based handoff (`.egg-state/agent-outputs/<prefix>-epic-apply.json`)
for the artifact write. The dedicated MCP tool registration is a
planned follow-up; the file-based path lands first because it's
serviceable end-to-end without new sandbox-side tools.

The plan-gate Stop/Continue fork itself (TASK-1-16 dispatch) and
the orchestrator-side post-apply hook that reads the artifact JSON
and merges into `Pipeline.set_epic_apply()` are still deferred to a
follow-up — but the foundation primitives, state-store, env-exports,
and role-roster wiring are now in place so those follow-ups don't
need to re-touch this surface.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
james-in-a-box Bot pushed a commit that referenced this pull request May 12, 2026
…y + N1

reviewer_code v3 blocking findings, all addressed:

* **#1 JQL injection** — new ``_validate_jira_key`` (regex
  ``[A-Z][A-Z0-9_]*-\d+``) runs on every epic_key BEFORE
  interpolation into JQL. Defends against a value like
  ``ENG-1" OR project=BAR`` terminating the quoted operand and
  injecting arbitrary clauses.
* **#2 No JQL pagination** — ``_run_jql`` now loops on
  ``nextPageToken`` until ``isLast=true`` or the cursor is omitted.
  Hard cap of 200 pages × 100 results = 20k children before emitting
  a structured warning and breaking.
* **#3 Status-only idempotency check** — ``_get_current_state``
  fetches ``status,resolution`` and ``transition_to_wont_do`` now
  short-circuits when ``statusCategory.key == "done"`` AND
  ``resolution.name`` is a Won't-Do name. Matches the common
  Atlassian workflow shape.
* **#4 Raw comment body** — comments are wrapped in ADF via the new
  ``_wrap_text_as_adf`` helper. Atlassian REST API v3 rejects plain
  strings for issue-comment bodies.
* **#5 ``get_epic_apply`` swallowing errors** — malformed JSON /
  failed Pydantic validation now log a structured
  ``epic_apply_artifact_invalid`` warning. Apply step's "no prior
  artifact" path still sees ``None``, but operators see the corruption.
* **#6 Mutual-exclusivity validator** — Pipeline ``@model_validator``
  refuses to construct a pipeline with both ``jira_ticket`` and
  ``jira_epic_key`` set.
* **#7 Lossy description hash** — new ``compute_description_sha256``
  hashes canonical ADF (`json.dumps(sort_keys=True,
  separators=(",", ":"))`) for dicts and UTF-8 for strings. The
  refine input gatherer now uses this helper.
* **#9 Audit log holes** — every transition exit path emits an
  ``orch_jira_transition_attempt`` line with ``outcome=`` matching
  the path: ``credentials_unavailable``, ``feature_flag_disabled``,
  ``status_fetch_failed``, ``already_in_state``,
  ``transition_not_found``, ``post_failed``, ``applied``.
* **#10 Feature-flag enforcement** — ``_post_transition`` checks the
  flag too (defence-in-depth). Future callers that go directly to
  the private method can't bypass the opt-in.
* **#11 ``httpx.Client`` never closed** — new ``close()`` method
  plus ``__enter__``/``__exit__`` so the orchestrator's shutdown
  hook can release pooled connections.
* **#12 ``__repr__`` token leak** — ``JiraCredentials.api_token``
  is now declared with ``field(repr=False)``; ``repr(creds)``
  emits ``JiraCredentials(base_url='...', username='...')`` only.

reviewer_code v4 BLOCKER N1 — agent-outputs file consumer:

* New module ``orchestrator/epic_apply_merge.py`` exporting
  ``merge_epic_apply_from_agent_outputs(pipeline, ...)``. Reads
  ``.egg-state/agent-outputs/<prefix>-epic-apply.json``, validates
  against the ``EpicApplyArtifact`` schema, and merges into
  ``pipeline.set_epic_apply()``. Re-runs union by
  ``(kind, target, summary_hash)`` for ``applied_edits`` and by
  ``child_key`` for ``wont_do_batch`` / ``in_flight_gates`` so
  partial-batch state survives re-spawns.
* Wired into the phase-success path in
  ``orchestrator/routes/pipelines.py`` so refine and plan
  completions automatically merge the agent's artifact.

``make lint`` passes end-to-end.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
james-in-a-box Bot pushed a commit that referenced this pull request May 12, 2026
Re-proposal addressing reviewer_code NACK on v1. The six blocking
findings were all "test coverage exists for the feature but doesn't
exercise the specific v5 mitigation, so a regression that re-introduces
the original bug would slip through". Each is now closed:

1. **`test_jira_reassess_detection.py::TestRunJql`** — added five
   pagination tests covering reviewer_code v3 #6 mitigation:
   `test_paginates_via_next_page_token` (3 pages with cursor threading
   end-to-end), `test_paginates_via_envelope_wrapped_response` (gateway
   `make_success` envelope unwrap), `test_pagination_stops_when_next_page_token_missing`,
   `test_pagination_stops_when_next_page_token_not_a_string`, and
   `test_pagination_hard_cap_terminates_loop` (200-page cap on infinite
   loops). Pre-fix code that returns after page 1 fails the multi-page
   tests; pre-cap code spinning forever fails the cap test.

2. **`test_jira_transitions_client.py::TestHappyPath::test_short_circuits_on_done_status_with_wont_do_resolution`**
   — exercises the resolution-branch of the already-in-state check
   (reviewer_code v3 #7 mitigation). Mocks the common Atlassian shape
   (status=Done + statusCategory.key=done + resolution=Won't Do), asserts
   `result.status == "already_in_state"` and that POST was NOT issued.
   Companion `test_does_not_short_circuit_on_done_with_other_resolution`
   pins the negative case (Done + resolution=Fixed → POST issued).

3. **`test_jira_transitions_client.py::TestHappyPath::test_post_body_wraps_comment_in_adf_document`**
   — asserts the EXACT ADF document shape (`{"type": "doc", "version": 1,
   "content": [{"type": "paragraph", "content": [{"type": "text", "text": …}]}]}`)
   for the comment body (reviewer_code v3 #8 mitigation). Pre-fix code
   that sends a raw string would slip past the original `"comment" in
   body["update"]` smoke check; this test pins the canonical ADF shape
   so a regression surfaces. Companion `test_empty_comment_omits_update_block`
   pins the empty-string fallback (no ADF wrapper for `""`/whitespace).

4. **`test_epic_apply_artifact.py::TestGetEpicApplyMalformedWarning`**
   — three tests (malformed JSON / JSON-but-schema-invalid / absent)
   covering reviewer_code v3 #10 mitigation. Patches
   `models._models_logger.warning` (the orchestrator uses egg_logging /
   structlog which bypasses caplog) and asserts the
   `epic_apply_artifact_invalid` event is emitted with the correct
   `reason` (`json_decode_failed` vs `pydantic_validation_failed`) and
   `pipeline_id` fields. Absent-artifact path is silent (no false
   warnings).

5. **`test_epic_apply_artifact.py::TestJiraTicketAndEpicKeyMutualExclusivity`**
   — five tests for the model-validator at `orchestrator/models.py:1243-1263`
   (reviewer_code v3 #11 mitigation). Asserts ValidationError when BOTH
   `jira_ticket` and `jira_epic_key` are set, AND that single-field
   pipelines (only `jira_ticket`, only `jira_epic_key`, neither) still
   work, AND that `jira_parent_epic_key` doesn't sidestep the
   mutual-exclusivity rule.

6. **`test_jira_epic_inputs.py::TestComputeDescriptionSha256`** — eight
   tests with non-circular assertions (every expected hash computed
   independently of the production helper). Covers: key-order invariance
   on ADF dicts (`sort_keys=True` mandate), ADF-vs-flattened-text
   distinction (the whole point of #7), plain-string utf-8 encoding,
   unicode utf-8 encoding, None → empty-string sha256 (with the
   well-known `e3b0c4…b855` digest pinned independently), unknown-shape
   fallback to `str(value).encode("utf-8")`, ADF non-ASCII without
   double-encoding (`ensure_ascii=False`), and separator-compactness
   (`separators=(",", ":")`). A refactor that drops any of these
   canonicalisation knobs surfaces a different hash and fails the test.

Also (caught by the new pagination tests as I authored them) — the
production pagination loop at `orchestrator/jira_epic_detect.py:271-272`
correctly only handles envelope-wrapped responses
(`response.get("data")` for the pagination cursor); test fixtures now
mirror that shape (matches the gateway's `make_success` envelope).

Plus one polish: `test_pipeline_prompts.py::test_plan_non_epic_omits_epic_section`
dropped an over-optimistic `slice-DAG` positive assertion — that
framing is layered on by higher-up builders, not `_build_phase_prompt`
directly. The byte-clean-of-epic check (the actual regression guard)
is retained.

Counts: 1137 tests pass (up from 1119), 9 skipped (kubectl-gated
integration scaffolds), 1.75s end-to-end via
`PYTHONPATH=shared:gateway:orchestrator python -m pytest <17 files>`.
`make lint` exits 0 (ruff check + ruff format + mypy + size-cap
warnings only).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dependencies Pull requests that update a dependency file github_actions Pull requests that update GitHub Actions code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant