Skip to content

[6669] test(gate): Rename a session between turns and assert the agent was told - #6673

Merged
mmabrouk merged 2 commits into
release/v0.115.3from
chore/release-1153-gate-rename-cell
Sep 8, 2026
Merged

[6669] test(gate): Rename a session between turns and assert the agent was told#6673
mmabrouk merged 2 commits into
release/v0.115.3from
chore/release-1153-gate-rename-cell

Conversation

@mmabrouk

@mmabrouk mmabrouk commented Sep 8, 2026

Copy link
Copy Markdown
Member

Context

The gate cannot see a per-turn fact that never reaches the agent. #6661 shipped through a green matrix: rename a session, ask the agent what it is called, and it answers the name from before the rename, on every turn after that too.

Two things hid it. No cell renames a session between two turns, and no cell asserts on the session facts at all. The three facts (the agent's display name, the session's name, the first-turn flag) reach the harness only as prompt text on turnContext, so no SSE frame reflects them and no stored row records them. Every cell in the matrix reads frames and side effects, so all of them were blind.

Closes #6669.

Changes

resources/matrix_n1_session_context.py drives one session on the path the playground posts, {BASE}/services/agent/v0/invoke, and asserts on values the model cannot have seen.

  1. An echo probe opens the session.
  2. Rename the session with PUT /sessions/streams/header, the route the inline rename in the chat panel uses, read the header back, then ask for the name.
  3. Rename again, then ask with "use only THIS turn's session facts". The previous name is in the transcript by now, from the agent's own reply, and the current one exists only in the stored header. Answering the previous one is the exact shape of [bug] Playground turns carry no session context: the agent is never given the session name #6661.
  4. Ask the agent for its own display name, which is set on the workflow at creation and spoken nowhere.
  5. Post a forged meta.session_context naming the session something else. The service must ignore it.

Every expected value carries a random token minted for the run, so a transcript-derived answer cannot match one.

Two controls keep a FAIL honest. The echo probe must come back with a literal token from its own user message, or the cell reports INCONCLUSIVE instead of blaming the transport. Every rename is read back before the ask, so a rename that did not land fails as a rename.

The cell is wired into path_triggers.py for the SDK session-context module, the platform prompt renderer, the agent handler, and the API's session-context resolver, into SKILL.md as a mandatory cell, and into coverage.md.

Two changes to the shared helper in qa_matrix_lib.py:

  • invoke now documents that it posts to the /services path exactly like the browser, and that nothing the API's invoke prelude does applies there. That is the assumption [bug] Playground turns carry no session context: the agent is never given the session name #6661 rested on.
  • invoke takes an optional meta, so a cell can forge what the API would otherwise stamp and prove the service refuses it. AGENTA_SERVICE_BASE moves only the turns to a hand-run service, so a fix can be gate-verified before it is deployed. It prints a banner and every result records the service_base it used.

Why this cell asserts on model prose

The gate's own rule is to assert on the wire and on side effects, never on what the model says. There is no surface here. turnContext is a prompt string on the service-to-runner payload, the runner prepends it and logs nothing, and it is deliberately kept out of request.messages and out of persisted user input so a replay cannot duplicate it. The stored turn row carries harness, sandbox and timing only. The transport half is pinned by unit tests instead, in test_wire_contract.py for the payload field and sandbox-agent-orchestration.test.ts for the prepend. This cell owns the journey. The random tokens are what make the prose evidence honest, and the docstring says so and names the date the surfaces were checked.

Tests

The gate's own unit tests: 313 passed. The new cell is registered in the silent-turn invariant's wired list, so test_qa_matrix_lib_silent_turns.py now checks that it folds the invariant into its verdict.

Live, on a local EE dev stack with an ephemeral account, harness pi_core, model openai/gpt-4.1-mini through an OpenRouter connection, sandbox local. The same backend under both runs, so the service is the only variable.

Service under test Result
The deployed stack, which does not have #6667 FAIL, exit 1, all four steps
A service built from #6667 PASS, exit 0

The FAIL reproduces both halves of the bug. The agent answered AGENTS for the session name and Pi for its own name, neither of which is a fact it was given, and it repeated the forged name verbatim. Both controls passed in both runs, so neither verdict can be blamed on the model or on a rename that did not land.

ruff format and ruff check clean at the CI-pinned 0.15.12. Evidence is in ~/agenta-qa-evidence/2026-09-08-gate-n1-session-context/.

Notes for reviewers

The cell is red against release/v0.115.3 until #6667 lands. That is the expected state: it is the regression test for a bug the release branch still has.

AGENTA_SERVICE_BASE is a new lever that points turns at a service nobody deployed. It is loud on stderr and recorded in every result, and coverage.md says a release run must never set it. It is worth a second look anyway, because the skill already warns at length about an env fallback that silently ran a whole gate against the wrong deployment.

…as told

The gate could not see a per-turn fact that never reaches the agent. Issue #6661
shipped through a green matrix because no cell renamed a session mid-conversation
and no cell asserted on the session facts at all.

Add matrix_n1_session_context.py. It drives one session on the path the playground
posts, renames the session between turns through the route the UI uses, and asks
for the name, the agent's own display name, and the name again with a forged
meta.session_context in the body. Every expected value carries a random token
minted for the run and spoken nowhere, so a transcript-derived answer cannot match.
Two controls keep a FAIL honest: an echo probe and a read-back of the stored header
after every rename.

Wire it into path_triggers.py for the SDK session-context module, the platform
prompt renderer, the agent handler, and the API session-context resolver, into
SKILL.md as a mandatory cell, and into coverage.md.

Document in the shared invoke helper that it posts to the /services path exactly
like the browser, so nobody writes a cell that assumes an API-side stamp. Add an
optional meta argument for the forged control, and AGENTA_SERVICE_BASE so a fix can
be gate-verified before it is deployed.
@mmabrouk

mmabrouk commented Sep 8, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai review

@vercel

vercel Bot commented Sep 8, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
agenta-documentation Ready Ready Preview Sep 8, 2026 7:03pm UTC

Request Review

@coderabbitai

coderabbitai Bot commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

Review Change StackReview Change Stack

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Organization UI (inherited)

Review profile: CHILL

Plan: Advanced

Run ID: 8cdd3019-29d9-4e73-b13b-4addeb721835

📥 Commits

Reviewing files that changed from the base of the PR and between 2863a4d and e4d76d7.

📒 Files selected for processing (1)
  • .agents/skills/agent-release-gate/resources/matrix_n1_session_context.py

Disabled knowledge base sources:

  • Linear integration is disabled

You can enable these sources in your CodeRabbit configuration.


📝 Summary

Summary by CodeRabbit

  • New Features

    • Added automated coverage for session context during playground conversations, including renamed sessions and agent display names.
    • Added validation that client-supplied session context is ignored.
    • Added configurable service endpoint support and optional request metadata for QA tools.
  • Tests

    • Added controls for verifying session renames, literal-token responses, and silent-turn handling.
    • Expanded mandatory coverage triggers for session-context changes.

Walkthrough

The release gate adds a session-context matrix cell. It verifies renamed session facts, agent display names, and rejection of forged metadata. Shared QA helpers now support configurable service routing, display names, and request metadata. Path triggers and silent-turn tests include the new cell.

Changes

Session-context release-gate coverage

Layer / File(s) Summary
QA matrix transport extensions
.agents/skills/agent-release-gate/resources/qa_matrix_lib.py
Adds SERVICE_BASE, optional workflow display names, and optional invocation metadata.
Session-context journey cell
.agents/skills/agent-release-gate/resources/matrix_n1_session_context.py
Adds a multi-harness cell that renames sessions between turns, verifies stored headers, checks session facts, and rejects forged meta.session_context.
Mandatory coverage and validation wiring
.agents/skills/agent-release-gate/resources/path_triggers.py, .agents/skills/agent-release-gate/resources/test_qa_matrix_lib_silent_turns.py, .agents/skills/agent-release-gate/resources/coverage.md, .agents/skills/agent-release-gate/SKILL.md
Makes the cell mandatory for session-context source changes, includes the silent-turn invariant, and documents the coverage behavior.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Merge Risk: 🔵 Low · up to 2863a

The new session-context coverage is useful, but setup failures can prevent complete results and echo-control outcomes are reported inconsistently. These bounded gate reliability issues should be corrected or explicitly accepted.

Sequence Diagram(s)

sequenceDiagram
  participant MatrixCell as matrix_n1_session_context.py
  participant SessionAPI as Session API
  participant InvokeAPI as Agent invoke API
  participant Model
  MatrixCell->>SessionAPI: rename session
  MatrixCell->>SessionAPI: read stored header
  MatrixCell->>InvokeAPI: invoke turn
  InvokeAPI->>Model: provide turnContext
  Model-->>MatrixCell: return session and agent facts
  MatrixCell->>InvokeAPI: invoke forged metadata control
  Model-->>MatrixCell: omit forged token
Loading
🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Linked Issues check ⚠️ Warning The pull request adds the rename-between-turns journey, session-name and agent-name checks, forged metadata protection, path wiring, and supporting helper changes. However, the provided change summary… Add an explicit assertion that the per-turn session context contains the correct first-turn flag, and include the assertion in the cell's PASS/FAIL decision.
Docstring Coverage ⚠️ Warning Docstring coverage is 55.56% which is insufficient. The required threshold is 60.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 9 functions across 4 files. (2 skipped: 2… Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Out of Scope Changes check ✅ Passed The changes are within scope. The new cell, helper updates, path triggers, documentation, and wiring tests directly support the linked session-context gate requirements.
Title check ✅ Passed The title clearly and concisely describes the main change: testing session renames between turns and verifying that the agent receives the updated session context.
Description check ✅ Passed The description is directly related to the changeset and explains the new session-context gate cell, its controls, wiring, helper changes, and test results.
Full details: Linked Issues check

Explanation

The pull request adds the rename-between-turns journey, session-name and agent-name checks, forged metadata protection, path wiring, and supporting helper changes. However, the provided change summary does not show an explicit assertion for the required first-turn flag.

Full details: Docstring Coverage

Explanation

Docstring coverage is 55.56% which is insufficient. The required threshold is 60.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 9 functions across 4 files. (2 skipped: 2 unsupported.)

  • Fix all pre-merge checks with AI
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch chore/release-1153-gate-rename-cell

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
.agents/skills/agent-release-gate/resources/matrix_n1_session_context.py (1)

247-254: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Align the echo-control status with the documented INCONCLUSIVE outcome.

This path returns status: "FAIL" while the why text and the docs call the result INCONCLUSIVE. SKILL.md line 495 and coverage.md line 268 both state that the cell reports INCONCLUSIVE when the echo probe fails. A reader of results.json sees only status, so a model that cannot echo a literal token is recorded as a product failure.

Either record the distinction in a dedicated field (for example "inconclusive": True) or correct the two documents to say the cell FAILs loudly with an INCONCLUSIVE reason.


ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Organization UI (inherited)

Review profile: CHILL

Plan: Advanced

Run ID: 976e95a4-4a55-4522-bc73-c776dc7055be

📥 Commits

Reviewing files that changed from the base of the PR and between 653c51b and 2863a4d.

📒 Files selected for processing (6)
  • .agents/skills/agent-release-gate/SKILL.md
  • .agents/skills/agent-release-gate/resources/coverage.md
  • .agents/skills/agent-release-gate/resources/matrix_n1_session_context.py
  • .agents/skills/agent-release-gate/resources/path_triggers.py
  • .agents/skills/agent-release-gate/resources/qa_matrix_lib.py
  • .agents/skills/agent-release-gate/resources/test_qa_matrix_lib_silent_turns.py

Included review availability: Your plan provides up to 8 included reviews per hour; 4 remain after this review.

Comment thread .agents/skills/agent-release-gate/resources/matrix_n1_session_context.py Outdated
@coderabbitai

coderabbitai Bot commented Sep 8, 2026

Copy link
Copy Markdown
Contributor
⚠️ Action not completed

Already reviewed the last commit. Use @coderabbitai full review to rerun a review of the entire changeset.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

…ction

CodeRabbit review follow-up.

create_workflow ran before the try, so a non-200 or a transport error escaped
n1_for uncaught. Under --harness-all that aborted the whole run with a traceback
and printed no results, which is the outcome the handler comment exists to
prevent. It now runs inside the try, so the same classifier turns it into a SKIP
or a FAIL. wf is bound to None first and the archive in finally is guarded, since
there is nothing to archive when the create itself failed.

Add one-line docstrings to stored_session_name, n1_for and main.
@mmabrouk
mmabrouk merged commit f2605a9 into release/v0.115.3 Sep 8, 2026
5 of 7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant