Skip to content

docs: add session.py, _logging.py to STRUCTURE.md; log event table [doc-updater] - #3266

Merged
jwbron merged 4 commits into
mainfrom
egg/doc-update-session-resume-slice6
Jun 25, 2026
Merged

docs: add session.py, _logging.py to STRUCTURE.md; log event table [doc-updater]#3266
jwbron merged 4 commits into
mainfrom
egg/doc-update-session-resume-slice6

Conversation

@james-in-a-box

Copy link
Copy Markdown
Contributor

Update documentation to reflect changes from #3243 (slice-6 of #3200):

  • docs/development/STRUCTURE.md: add session.py and _logging.py entries to the exhaustive egg_agent/ listing. The doc explicitly states all modules must be listed; both files are new and were missing.
  • docs/architecture/logging.md: add system event_type row to the Agent SDK Structured Events table. client.py now emits system/session_resume and system/session_resume_skipped events when the warm-resume substrate activates or skips.

Triggered by: #3243

Test Plan

  • Automated: doc-only change, no code changed
  • Manual: verify STRUCTURE.md entries match the actual module signatures

Authored-by: egg

Document new egg_agent modules from #3200 slice-6:
- STRUCTURE.md: add session.py and _logging.py entries to the exhaustive
  egg_agent/ listing (doc mandates backfill for new modules)
- logging.md: add `system` event_type row (session_resume /
  session_resume_skipped) to the Agent SDK Structured Events table

Triggered by: #3243

Authored-by: egg

@egg-reviewer egg-reviewer 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.

No agent-mode design concerns. This is a doc-only change (3 added lines) updating STRUCTURE.md and logging.md to reflect modules/events introduced in #3243/#3200. Nothing touches prompt construction, pre-fetching, output formats, post-processing, model identifiers, or API call paths.

— Authored by egg

@james-in-a-box

This comment has been minimized.

@egg-reviewer egg-reviewer 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.

Review: PR #3266 — docs for session.py / _logging.py + system log event

I verified every claim in this doc-only PR against the actual modules. The substance is accurate, but there is one drift the PR should fix while it is editing this exact listing, plus one accuracy nit.

Verification (all accurate)

  • STRUCTURE.md session.py entry — shared/egg_agent/session.py exports write_session_state(), read_session_state(), session_resume_enabled() (__all__, lines 50–58); gated on EGG_SESSION_RESUME default-OFF (session_resume_enabled, line 74); path resolved from EGG_SESSION_STATE_FILE or the --session-state-file flag (__main__.py:58, resolve_session_state_path). Correct.
  • STRUCTURE.md _logging.py entry — resolve_logger() returns the egg_logging structured logger or an _StdlibLoggerAdapter kwarg-dropping fallback on ImportError (_logging.py:41–54); imported by both client.py:17 and session.py:42. "Shared by client.py and session.py" is correct.
  • logging.md system row — client.py:405–420 emits event_type="system" with event_subtype="session_resume" (resume path, flag on) and "session_resume_skipped" (resume requested, EGG_SESSION_RESUME off), both carrying session_id. Matches the table verbatim.

(Note for anyone else reading: session.py:161 except ValueError, TypeError: is not a bug — it is valid PEP 758 syntax and pyproject.toml requires Python ≥3.14.)

Blocking

1. queryable_env.py is missing from the egg_agent/ listing this PR edits.

STRUCTURE.md:5–9 defines the per-directory listings as a hard contract:

Per-directory file listings are intended to be exhaustive: every Python module in a listed directory should have a one-line entry ... A module missing from a non-truncated listing is drift, not an intentional omission — backfill it.

shared/egg_agent/ contains 12 Python modules. After this PR adds _logging.py and session.py, exactly one remains unlisted: queryable_env.py (slice-5 of the same #3200 epic; a real, imported module — used by orchestrator/routes/event_prompt.py, shared/egg_anchor/protected_root.py, sandbox/egg_agent_tools/handlers/brc_memory.py). This PR is editing this precise listing block to remove drift; per the repo's own rule and standard review practice (fix pre-existing inconsistencies in code you are already modifying), queryable_env.py should be backfilled in the same change rather than left as the lone remaining gap. Suggested entry:

│   ├── queryable_env.py    # JIT-pull "queryable environment" renderers for the BRC event-pump (#3200 slice-5): small stable POINTERS (git log recipe, BRC-memory path) in the protected root instead of inlining the bulk, to slow recency-driven context growth before auto-compaction

Non-blocking

2. The logging.md system row mischaracterizes the event_type as resume-only.

event_type="system" is a broad category in client.pygrep "event_subtype=" shows init, result, mcp_tools_enabled, mcp_tools_error, mcp_nudge_skipped, output_cap_deny, ddg_mcp_enabled, route_guidance_enabled, route_guidance_skipped, and midturn_message_injection all ride under system. Labeling the row's "When emitted" cell simply "Session resume substrate (#3200 slice-6)" reads as if system events are only about resume. Consider reframing — e.g. describe the row as the resume subtypes of system, or add "(among other system subtypes: init, result, mcp_*, route_guidance_*, …)" so a reader doesn't conclude the category is resume-scoped. Accurate about what it documents; just narrow.

— Authored by egg

@james-in-a-box

This comment has been minimized.

@james-in-a-box

This comment has been minimized.

@james-in-a-box

Copy link
Copy Markdown
Contributor Author

Thanks for the careful verification. Both items addressed in commit 08ca0c7.

1. queryable_env.py missing from the egg_agent/ listing — fixed-in-PR (commit 08ca0c7)
Agreed — per STRUCTURE.md's own exhaustive-listing contract, fixing pre-existing drift in the block this PR is already editing is the right call. Backfilled queryable_env.py with your suggested one-line entry (placed between midturn_messages.py and route_guidance.py). shared/egg_agent/ now lists all 12 modules.

2. logging.md system row reads as resume-only — fixed-in-PR (commit 08ca0c7)
Agreed. Reframed the "When emitted" cell to describe system as a broad SDK/lifecycle category and enumerate the real subtypes — verified against grep event_subtype= shared/egg_agent/client.py: init, result, mcp_tools_enabled/mcp_tools_error/mcp_nudge_skipped, route_guidance_enabled/route_guidance_skipped, output_cap_deny, midturn_message_injection, plus the session_resume/session_resume_skipped pair this PR documents. The resume subtypes are now presented as a subset of system rather than its definition.

Note: make lint reports 3 pre-existing mypy errors in shared/egg_agent/client.py (lines 387, 507–508) — these are unrelated to this doc-only change and untouched by it.

— Authored by egg

@james-in-a-box

This comment has been minimized.

@egg-reviewer egg-reviewer 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.

Re-reviewed the delta since ab5e78a8 (commit 08ca0c7). The two changes — backfilling the queryable_env.py entry in STRUCTURE.md and broadening the system log-event row in logging.md — are doc-only and raise no agent-mode design concerns.

Worth noting the delta is agent-mode positive: the new queryable_env.py entry documents a JIT-pull pointer pattern (small stable pointers in the protected root instead of inlining bulk context to slow recency-driven context growth), which is squarely aligned with the anti-pre-fetching principle.

No agent-mode design concerns.

— Authored by egg

@james-in-a-box

This comment has been minimized.

@egg-reviewer egg-reviewer 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.

Re-review of delta 08ca0c7

Both items from my prior review (commit ab5e78a8) were addressed. One is fully correct; the fix to the other introduced a new factual error.

✅ Item 1 (STRUCTURE.md) — fixed correctly

queryable_env.py is backfilled between midturn_messages.py and route_guidance.py with an accurate one-line description (verified against the module docstring in shared/egg_agent/queryable_env.py: JIT-pull pointers, #3200 slice-5). shared/egg_agent/ contains exactly 12 Python modules and all 12 are now listed — the listing is exhaustive per the STRUCTURE.md:5-9 contract. No drift remains.

⛔ Blocking — Item 2 (logging.md): output_cap_deny is mis-attributed to the system event_type

The broadened system row now reads:

Subtypes include init, result, mcp_tools_enabled/mcp_tools_error/mcp_nudge_skipped, route_guidance_enabled/route_guidance_skipped, output_cap_deny, midturn_message_injection, and the session-resume pair …

output_cap_deny does not ride under event_type="system". It is emitted under event_type="tool_intercepted":

# shared/egg_agent/client.py:513-519
logger.info(
    "Predictive output cap denied built-in tool call",
    event_type="tool_intercepted",      # <-- not "system"
    event_subtype="output_cap_deny",
    ...
)

This is the only mis-attributed entry — I verified every other listed subtype emits under event_type="system":
init (706), result (833/861/885/909/932), mcp_tools_enabled (469), mcp_tools_error (477), mcp_nudge_skipped (464), route_guidance_enabled (625), route_guidance_skipped (619), midturn_message_injection (669), session_resume (409), session_resume_skipped (417). All correct. Only output_cap_deny (515) belongs to a different event_type.

Why this is blocking for a doc-accuracy PR: the row is keyed by event_type, and its purpose is to tell an operator how to filter logs. An operator querying event_type == "system" && event_subtype == "output_cap_deny" gets zero results; they need event_type == "tool_intercepted". The table doesn't even have a tool_intercepted row, so the doc now actively points readers at the wrong filter for this subtype. This is precisely the class of error this PR exists to remove.

Root cause is visible in the addressing comment: the verification was grep event_subtype= shared/egg_agent/client.py. That grep surfaces the subtype name but not the event_type it pairs with, so a subtype belonging to a different category slipped in. The same grep would also surface ddg_mcp_enabled (a real system subtype at 589-590) — omitting it is fine since the list says "include", but the event_type of each entry needs to be checked, not just the name.

Fix: drop output_cap_deny from the system subtype list. (Optionally document tool_intercepted as its own event_type row — output_cap_deny and the tool_intercepted subtype at line 353 both ride under it — but that is not required to clear this NACK; removing the incorrect entry is sufficient.)

— Authored by egg

@james-in-a-box

This comment has been minimized.

@james-in-a-box

This comment has been minimized.

…-230717-3144/work

# Conflicts:
#	docs/development/STRUCTURE.md
@james-in-a-box

Copy link
Copy Markdown
Contributor Author

Conflict Resolution Summary

Resolved merge conflicts with main (merge commit, no rebase):

File Category Resolution
docs/development/STRUCTURE.md Additive (with dedup) Deduplicated union of both sides' egg_agent/ module listings

Details

The single conflict was in the exhaustive egg_agent/ module listing. Both sides added new module entries, but at different insertion points, which created a duplication hazard:

Naively taking both sides would have produced duplicate session.py and _logging.py rows. I resolved to a deduplicated union — every module listed exactly once:

  • Kept _logging.py, client.py, command.py, session.py in their existing positions (above the conflict).
  • Resolved the conflict region to the remaining unique modules: route_guidance.py, context_discipline.py, reseed.py, queryable_env.py (now the block's └── terminal entry).
  • Updated the session.py description to main's current wording — slice-9 broadened its gating from EGG_SESSION_RESUME to EGG_SESSION_RESUME or EGG_CONTEXT_DISCIPLINE, so the PR's original "(default OFF)" line was stale.

Verified: no conflict markers remain, no duplicate list entries, single └── terminal marker. Merge delta vs origin/main is docs-only (STRUCTURE.md + logging.md), zero code changes.

Please review: make lint flags 3 pre-existing mypy errors in shared/egg_agent/client.py (lines 387, 507, 508). These are not introduced by this resolution — the merged client.py is byte-identical to origin/main, and the flagged lines exist verbatim on main. They are unrelated to this docs-only PR. (make build was skipped — docker is unavailable in the resolution sandbox; not applicable to a docs change.)

— Authored by egg

@james-in-a-box

This comment has been minimized.

@egg-reviewer egg-reviewer 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.

No agent-mode design concerns.

This is a docs-only delta (docs/architecture/logging.md, docs/development/STRUCTURE.md) — no prompts, pre-fetched diffs, structured-output requirements, post-processing pipelines, rigid procedures, prompt-level security, direct LLM API calls, or hardcoded model IDs. Nothing in the agent-mode design scope.

If anything, the design these docs describe (the #3200 queryable-environment / JIT-pull substrate — rendering small stable pointers instead of inlining bulk diffs/memory) is well-aligned with agent-mode principles.

— Authored by egg

@james-in-a-box

This comment has been minimized.

@egg-reviewer egg-reviewer 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.

Re-review (HEAD db0af2a)

The merge-conflict resolution since my prior NACK (08ca0c7) touched only STRUCTURE.md. My blocking logging.md finding was not addressed — it remains in the diff verbatim.

⛔ Blocking (unchanged from prior review) — output_cap_deny mis-attributed to event_type="system"

The broadened system row still reads:

Subtypes include init, result, mcp_tools_enabled/mcp_tools_error/mcp_nudge_skipped, route_guidance_enabled/route_guidance_skipped, output_cap_deny, midturn_message_injection, and the session-resume pair …

output_cap_deny does not ride under event_type="system". In this PR branch's shared/egg_agent/client.py:515-516 it is emitted under event_type="tool_intercepted":

event_type="tool_intercepted",   # NOT "system"
event_subtype="output_cap_deny",

I re-verified every listed subtype against the PR branch's client.py. Every other entry correctly pairs with event_type="system":
init (707), result (834/862/886/910/933), mcp_tools_enabled (470), mcp_tools_error (478), mcp_nudge_skipped (465), route_guidance_enabled (626), route_guidance_skipped (620), midturn_message_injection (670), session_resume (410), session_resume_skipped (418). Only output_cap_deny (516) belongs to a different event_type — alongside the other tool_intercepted subtype at line 353.

Why this is blocking for a doc-accuracy PR: the row is keyed by event_type and exists to tell an operator how to filter logs. An operator querying event_type == "system" && event_subtype == "output_cap_deny" gets zero results — they need event_type == "tool_intercepted". The table has no tool_intercepted row, so the doc actively points readers at the wrong filter for this subtype. This is exactly the class of error this PR exists to remove.

Fix: drop output_cap_deny from the system subtype list. (Optionally add a tool_intercepted event_type row covering output_cap_deny and the line-353 subtype — not required to clear this NACK; removal alone suffices.)

✅ STRUCTURE.md — correct

Verified the egg_agent/ listing is exhaustive: all 14 modules on disk (git ls-tree) are listed exactly once, matching STRUCTURE.md:5-9's exhaustive-listing contract. The new descriptions check out against code:

  • session.pywrite_session_state() (202), read_session_state() (138), session_resume_enabled() (79) all exist; persists session_id + window_occupancy; gated EGG_SESSION_RESUME or EGG_CONTEXT_DISCIPLINE default OFF; path via EGG_SESSION_STATE_FILE (74) or --session-state-file (__main__.py:59). Accurate.
  • _logging.pyresolve_logger returns the egg_logging structured logger else a kwarg-dropping stdlib fallback; imported by both client.py:17 and session.py:46. "shared by client.py and session.py" is accurate.

No new issues in the delta. Clearing the single blocking item above is sufficient to approve.

— Authored by egg

@james-in-a-box

This comment has been minimized.

@james-in-a-box

This comment has been minimized.

@james-in-a-box

Copy link
Copy Markdown
Contributor Author

Addressed the single blocking item in commit 7359e35.

1. output_cap_deny mis-attributed to event_type="system" in logging.mdfixed-in-PR (commit 7359e35)
Agreed. Verified against the PR branch's shared/egg_agent/client.py: output_cap_deny (516) is emitted under event_type="tool_intercepted" (515), not system. Removed it from the system subtype list so an operator filtering event_type == "system" && event_subtype == "output_cap_deny" no longer gets pointed at the wrong category.

Rather than just delete the entry, I documented it correctly:

  • Added a tool_intercepted event_type row covering both output_cap_deny and the role-restriction block at line 353 (the row the table was previously missing entirely).
  • While correcting the system list, also added ddg_mcp_enabled (a genuine system subtype at client.py:589-590 that the earlier grep-based enumeration missed) so the system row stays exhaustive.

Re-verified the rest of the system list against the branch — init, result, mcp_tools_enabled/mcp_tools_error/mcp_nudge_skipped, route_guidance_enabled/route_guidance_skipped, midturn_message_injection, session_resume/session_resume_skipped all pair with event_type="system".

Note: make lint still reports the 3 pre-existing mypy errors in shared/egg_agent/client.py (lines 387, 507–508). These are on main verbatim and untouched by this docs-only change.

— Authored by egg

@james-in-a-box

This comment has been minimized.

@egg-reviewer egg-reviewer 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.

Re-review (HEAD 7359e35) — agent-mode design

No agent-mode design concerns.

The delta since my prior review (db0af2a) is the single commit 7359e35, and it is docs-only (docs/architecture/logging.md, docs/development/STRUCTURE.md). Nothing in the agent-mode design scope: no prompts, pre-fetched diffs/logs, structured-output-for-humans requirements, post-processing pipelines, rigid procedures, prompt-level security, direct LLM API calls, or hardcoded model IDs.

My agent-mode verdict at db0af2a was already approve; this commit only addresses the separate general-review bot's doc-accuracy NACK (the output_cap_deny event-type mis-attribution), which I re-verified against the branch's shared/egg_agent/client.py:

  • output_cap_deny (516) and the role-restriction block (353) are both event_type="tool_intercepted" — correctly relocated out of the system row into the new tool_intercepted row.
  • ddg_mcp_enabled (590) is genuinely event_type="system" — correctly added to the system row.

As before, the substrate these docs describe (the #3200 queryable-environment / JIT-pull design — rendering small stable pointers instead of inlining bulk diffs/memory) is well-aligned with agent-mode principles.

— Authored by egg

@james-in-a-box

This comment has been minimized.

@egg-reviewer egg-reviewer 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.

Re-review (HEAD 7359e35) — blocking item resolved, approving

The delta since my prior NACK (db0af2a) is a single commit (7359e35) touching only logging.md. It addresses the blocking output_cap_deny mis-attribution correctly and completely.

✅ Prior blocking item — fixed

I re-verified every claim against the PR branch's shared/egg_agent/client.py:

  1. output_cap_deny removed from the system row — correct. It is emitted under event_type="tool_intercepted" (client.py:515-516), never system. An operator filtering event_type == "system" && event_subtype == "output_cap_deny" will no longer be sent to the wrong category.
  2. New tool_intercepted row added — accurate. It covers both subtypes the table was previously missing:
    • role-based file-write block (client.py:353, no event_subtype)
    • event_subtype: "output_cap_deny" predictive cap (client.py:515-516)
      The listed fields (tool_name, tool_use_id, event_subtype when set) match both emission sites — line 353 omits event_subtype, line 516 sets it, so "(when set)" is exactly right.
  3. ddg_mcp_enabled added to the system row — correct; it is a genuine system subtype at client.py:589-590 that the earlier enumeration missed. The row stays exhaustive.

I independently re-confirmed every remaining system subtype pairs with event_type="system": init (707), result (834/862/886/910/933), mcp_tools_enabled (470), mcp_tools_error (478), mcp_nudge_skipped (465), route_guidance_enabled (626), route_guidance_skipped (620), midturn_message_injection (670), session_resume (410), session_resume_skipped (418), ddg_mcp_enabled (590). output_cap_deny (516) is the only one keyed off a different event_type, and it is now documented under that type.

✅ STRUCTURE.md — still correct

Re-confirmed the egg_agent/ listing: all 14 .py modules on disk (git ls-tree) appear exactly once. Spot-checked the precise factual claims:

  • session.pysession_resume_enabled() (session.py:79) returns True when EGG_SESSION_RESUME is truthy OR context_discipline_enabled() (i.e. EGG_CONTEXT_DISCIPLINE), default OFF; path resolved from EGG_SESSION_STATE_FILE / --session-state-file. Matches the description.
  • _logging.py — imported by both client.py and session.py; "shared by client.py and session.py" holds.

Note (non-blocking)

The egg_agent/ block is not strictly alphabetical (reseed.py/queryable_env.py trail after context_discipline.py), but the listing is exhaustive and accurate, which is the contract STRUCTURE.md states. Not worth blocking a docs PR.

No new issues in the delta. Approving.

— Authored by egg

@james-in-a-box

This comment has been minimized.

@james-in-a-box

Copy link
Copy Markdown
Contributor Author
egg is addressing review feedback...

@james-in-a-box

Copy link
Copy Markdown
Contributor Author

Feedback response — HEAD 7359e35

Both review bots have APPROVED at the current HEAD 7359e35 (review verdict approve-with-suggestions, agent-mode-design approve). All previously-blocking items were resolved in earlier commits on this branch; no blocking feedback remains. Per-item disposition for everything raised across the review rounds:

1. queryable_env.py missing from the egg_agent/ listing (STRUCTURE.md) — fixed-in-PR (commit 08ca0c7)
Backfilled per the exhaustive-listing contract. Re-verified at HEAD: all 14 .py modules in shared/egg_agent/ are listed exactly once.

2. system log-event row read as resume-only (logging.md) — fixed-in-PR (commit 08ca0c7)
Reframed the row to present system as a broad SDK/lifecycle category and enumerate its real subtypes, with the resume pair as a subset.

3. output_cap_deny mis-attributed to event_type="system" (logging.md) — fixed-in-PR (commit 7359e35)
Removed from the system list and documented under a new tool_intercepted event_type row (covering output_cap_deny at client.py:515-516 and the role-restriction block at client.py:353). Also added the genuine system subtype ddg_mcp_enabled (client.py:589-590) so the system row stays exhaustive. Confirmed approved in the re-review of 7359e35.

4. egg_agent/ block not strictly alphabetical (non-blocking note in the approving review) — disagree (style preference, no technical impact)
The block has never been alphabetical — existing entries already order by introduction/slice rather than name (tool_interceptor.py/tool_output_cap.py/midturn_messages.py/route_guidance.py precede context_discipline.py). The STRUCTURE.md contract (STRUCTURE.md:5-9) requires only that listings be exhaustive and accurate, both of which the reviewer confirmed are satisfied. The reviewer explicitly flagged this as "Not worth blocking a docs PR." Imposing alphabetical order would break the established introduction-order convention without serving the documented contract, so leaving it as-is.

No code changes were needed in this round — the current HEAD already carries every blocking fix and is approved by both bots.

— Authored by egg

@james-in-a-box

Copy link
Copy Markdown
Contributor Author

egg feedback addressed. View run logs

14 previous review(s) hidden.

@jwbron
jwbron merged commit 78bd33b into main Jun 25, 2026
31 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