[issue-3200][slice-1/10] Token-occupancy capture (prerequisite, AC-1) - #3236
Conversation
…xt discipline Refine analysis for issue #3200 (protected directive root + queryable environment + deterministic threshold reseed). Grounds all issue code references against the tree, maps the build to existing code, states the central hypothesis + measurement plan, and registers cq-1 (pipeline scope) and cq-2 (prototype reviewer role). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Operator scope correction: build the full protected-root / queryable- environment / threshold-reseed mechanism wired for ALL BRC roles (producers and reviewers); build measurement tooling only (token-occupancy capture + metric surfaces) but run no measurement and gate nothing on measured results. Drop the single-reviewer-prototype framing; cq-2 moot, cq-1 collapsed to one decided scope. Measurement, go/no-go, generalization, recursion escalation, and the preserved fallback deferred to a follow-up. Rewrote acceptance criteria to the full-build-all-roles shape. All grounded technical content preserved. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…shold reseed Task breakdown for BRC context discipline, scoped per resolved HITL (cq-1/cq-2): full build across ALL event-pump roles + measurement tooling only; measurement, go/no-go, generalization gate, recursion escalation, and fallback deferred. 8 phases / 19 tasks, sequenced on the token-occupancy-capture prerequisite. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…threshold reseed Render task_planner DAG to the gate-expected .egg-state/drafts/3200-plan.md. 8 phases / 19 tasks; scope per resolved HITL cq-1/cq-2 (full build all roles, measurement tooling only; measurement/go-no-go/generalization/recursion/fallback deferred). AC-1..AC-5 carried from refine. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Risk assessment for the BRC context-discipline build (protected root + queryable environment + threshold reseed, all roles, measurement tooling only). 11 risks grounded against the confirmed refine analysis and the working tree: OPEN substrates #3186 (session resume) and #3189 (deterministic anchors); silent-failure seams in real-window resolution, ResultMessage.usage occupancy source, and protected-root determinism vs the timestamp-heavy egg_anchor model; and the no-measurement fleet-wide rollout. Primary controls: feature flag with full-context OFF state, and gating the root on #3189 anchor content. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…nto egg/issue-3200-risk_analyst/work
Contract populator parses the # yaml-tasks fence at plan-completion; add it so the draft populates. 8 phases / 19 tasks mirroring the prose DAG. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adds plan_reconciliation: R3/R4/R6/R7/R8/R10 substantially addressed by the 8-phase DAG; three gaps remain open — R1 (#3186 resume substrate not built as a task), R5 (#3189 anchor content assumed present but absent from egg_anchor BRCState; consensus-integrity hazard), R9 (full-context path removed with no feature-flag kill switch). Plus R2 refinement: None occupancy must bias toward over-reseed, not under. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…nto egg/issue-3200-risk_analyst/work
Phase gate, contract population, and resume read the risk-analyst-output from .egg-state/agent-outputs/3200-risk_analyst-output.json. Add it at that path with overall_risk/verdict mirror keys for downstream readers. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…verlap) Slices share shared/egg_agent(+tests) and orchestrator(+tests), so independent branches would collide at integration. Add linear dependencies 1->2->...->8 (<=1 parent each, superset of the logical DAG). Update prose DAG to distinguish logical deps from the serialized execution chain. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Grounded architect plan artifact: token-occupancy capture, protected-root/ queryable-environment split (all roles), Python-side resume-vs-reseed gate at min(400k, 0.80 x real_backend_window), measurement surfaces (emit-only). Surfaces the critical dependency that AC-3's gate requires building the minimal session-resume substrate (#3186 unimplemented today). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Mirror of the architect plan artifact at the canonical .egg-state/agent-outputs/3200-architect-output.json the phase gate reads, plus a plan_reconciliation against the merged task_planner DAG and risk_analyst: flags resume-substrate (OQ1), #3189 anchor-content sourcing, and kill-switch. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
8-slice serialized chain (file-overlap) mapping the four components: occupancy capture, real-window resolver, byte-stable protected root, JIT queryable env, restart-stable session state, Python resume-vs-reseed gate + minimal resume substrate (OQ1), all-roles behind a kill-switch flag, emit-only metrics. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…e-occupancy bias, kill-switch flag Resolves the v1 open-NACK barrier (reviewer_plan BLOCKER-1/2 + recommendation; risk_analyst B1-B4). v1 leaned on two OPEN substrates as if they existed: - B1: #3189 deterministic anchor CONTENT — BRCState carries none of the four fields; new phase 3 derives them from the BRC message record (hard prereq of the protected root). Grounding table corrected. - B2: #3186 resume substrate — client.py has zero resume= plumbing; new phase 6 lands resume=<session_id> + a defined no-warm-session cold-start fallback (hard prereq of the reseed). - B3: phase-8 None/unknown occupancy biases to reseed, never resume-below-threshold. - B4: phase-9 single feature flag; OFF retains today's full-context path (kill-switch, distinct from the out-of-scope verbatim fallback build). 8->10 phases, 19->23 tasks. JSON mirror regenerated to match. Serialized chain preserved (file-overlap #3046). Scope honors HITL cq-1/cq-2. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…C-1) Add an optional cumulative window-occupancy field to AgentResult (window_occupancy = cache_read + cache_creation + input from the SDK usage block) plus an optional raw token_usage breakout. Both default None and are non-breaking. In client.py stop dropping message.usage on the ResultMessage branch: compute occupancy defensively (absent/partial/non-dict usage -> None or 0-filled components, never an exception) and thread it through result_meta into every AgentResult build site (success, is_error, timeout, process/SDK error, generic exception). The pre-execution ImportError return correctly leaves occupancy None. Occupancy is the load-bearing signal for the #3200 threshold reseed; it is NOT billed input (it includes cache reads), so None biases callers to a safe reseed rather than a lossy resume. Covers task-1-1, task-1-2. task-1-3 (tests) owned by tester. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…-1, task-1-3) Add TestAgentResultOccupancyField + TestOccupancyCapture to tests/shared/egg_agent/test_client.py, driven through run_agent_async on the existing mock-SDK harness so they pin the observable AgentResult surface rather than the private _compute_occupancy helper. Coverage (AC-1 / task-1-3): - field defaults: window_occupancy and token_usage default None; legacy 4-positional construction still builds (non-breaking). - full usage -> occupancy == input + cache_read + cache_creation. - absent usage (None) -> occupancy None and token_usage None, no raise. - partial usage (missing key) -> sum of present components. - present-but-None sub-field -> coerced to 0, not a TypeError. - cache-dominated turn -> occupancy tracks the full resident window, not the ~50-token billed input (the core reseed-trigger requirement). - output_tokens excluded from occupancy but preserved in the token_usage breakout for the phase-10 measurement surfaces. - error build site also captures occupancy (every site populated, task-1-2). Threads an optional usage= param through the _make_result_msg helper (default None, backward compatible). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
There was a problem hiding this comment.
Contract re-verification — PR #3236 (slice-1/10, AC-1: token-occupancy capture)
Verdict: Approve (re-affirm). Incremental verification against my prior review at 102a4a12.
Delta since last review
The only PR-authored change since 102a4a12 is the merge commit 8835a00, which merges origin/egg/issue-3200/work (base) into the PR branch and resolves a conflict in .egg-state/contracts/issue-3200.json by taking the base branch's authoritative pipeline state.
- Slice-1 implementation is unchanged.
git diff 102a4a12 HEAD -- shared/egg_agent/ tests/shared/egg_agent/is empty.result.py,client.py, andtest_client.pyare byte-identical to what I verified last cycle, so the previously-verified AC-1 implementation still holds (no regression). - The orchestrator files in the raw delta are merge-ins, not new PR work.
decisions.py,pipelines.py, andtest_orphaned_driver_revival.pyat HEAD are identical to the base-branch tip (f592b01); they entered via the merge. The effective PR diff (origin/egg/issue-3200/work...HEAD) is cleanly scoped to slice-1:shared/egg_agent/client.py,shared/egg_agent/result.py,tests/shared/egg_agent/test_client.py(+ BRC history). They do not widen the PR's effective scope. - Contract conflict resolution is sound. The resolved contract keeps
slice-1=completewith correct task→commit linkage:task-1-1andtask-1-2→d0705780. No previously-verified state was rolled back.
Re-confirmed evidence (intact in current tree)
shared/egg_agent/result.py:53-54—window_occupancy: int | None = Noneandtoken_usage: dict | None = None, both optional/non-breaking, docstring defines occupancy = input + cache_read + cache_creation and excludes billed input (task-1-1).shared/egg_agent/client.py:76 _compute_occupancy()+last_assistant_usagesourced from the final top-level turn (parent_tool_use_id is None, line 732) and threaded into everyAgentResultbuild site (success ~833, and error/timeout/SDK/generic sites ~857/881/905). Absent/partial usage →None/0-filled, never raises (task-1-2).tests/shared/egg_agent/test_client.py:1679,1712—TestAgentResultOccupancyField+TestOccupancyCapturecover defaults, full/absent/partial usage, cache-dominated (occupancy ≠ billed input), final-turn-not-aggregate, sub-agent exclusion, and error-site capture (task-1-3 coverage present in-tree).
Notes for the human reviewer (non-blocking, pre-existing)
task-1-3is still markedpendingin the contract even though its test coverage exists in-tree. This is a contract-bookkeeping discrepancy that predates this delta (owned by the tester role), not introduced by the merge — flagging for completeness, not as a delta violation.- The orchestrator is unreachable, so
verify-criterioncould not be run this cycle. The contract's top-levelacceptance_criterialist is empty; slice-1's criteria are tracked at the slice/task level and are already marked complete.
No contract violations introduced by the delta. Previously-verified criteria still hold.
— Authored by egg
This comment has been minimized.
This comment has been minimized.
There was a problem hiding this comment.
Re-review: [issue-3200][slice-1/10] Token-occupancy capture — sub-agent filtering added ✅
I re-reviewed the current PR head (the prior-review commit 102a4a12 was squashed/rebased out of the branch, so I traced the full current diff of the three code files against the base rather than a git-range delta). The delta since my last approval is a single, focused addition: sub-agent (Task tool) turns are now excluded from last_assistant_usage — exactly the non-blocking concern I flagged in my prior approval. It is implemented correctly, with a real test. Approving.
🟡 (prior non-blocking) sub-agent messages polluting last_assistant_usage — RESOLVED
client.py:730-734 now gates the per-turn capture on both a present usage block and a top-level turn:
if (
message.usage is not None
and getattr(message, "parent_tool_use_id", None) is None
):
last_assistant_usage = message.usageI verified this is correct at the SDK level, not just structurally:
claude_agent_sdk/types.py:1030declaresAssistantMessage.parent_tool_use_id: str | None, and_internal/message_parser.py:175,177populates it fromdata.get("parent_tool_use_id")alongsideusage=data["message"].get("usage")(the raw per-API-call window block). Sub-agent turns carry a non-Noneparent_tool_use_id; top-level turns areNone(types.py:1544— "Always None for top-level conversation"). So filtering toparent_tool_use_id is Nonekeeps only the main session's resident window — the value the reseed decision needs.getattr(..., None)is appropriately defensive against SDK shapes lacking the attribute (and the test's mockAssistantMessagegainedparent_tool_use_idso the CI mock-SDK path exercises the same branch).
I hand-traced the capture/occupancy logic against the three relevant cases (main-then-subagent terminal turn, multi-step, all-subagent) and all resolve as intended: a trailing sub-agent turn no longer overwrites the main window; an all-sub-agent stream falls back to None → safe reseed.
🟡 (prior non-blocking) test couldn't surface the sub-agent overwrite — RESOLVED
test_subagent_turns_excluded_from_occupancy drives the real production path (run_agent_async → stream loop → _compute_occupancy): it streams a main-session turn (150k window) followed by a sub-agent turn (parent_tool_use_id="task-abc", 30k window) before the ResultMessage, and asserts window_occupancy == 150_000 with an explicit != 30_000 guard. Because the sub-agent turn is the terminal AssistantMessage, this test fails against the pre-fix code (which would capture 30k) — it pins the behaviour, not the factoring. No hand-built fixture bypasses the helper; no self-seeding golden.
What's still correct (carried over from my f3f42b3 approval)
- The original blocking fix is intact: occupancy is sourced from the final
AssistantMessage.usage(per-turn window), never the cumulativeResultMessage.usage.test_multistep_uses_final_turn_not_cumulative_aggregatestill guards the aggregate regression (asserts 150k,!= 373k). - All five build sites thread
_compute_occupancy(last_assistant_usage)/_usage_components(last_assistant_usage)(success:931,is_error:806/833, timeout:857, Process/SDK error:881, generic Exception:905); the pre-flightImportErrorsite keeps theNonedefault. Error/timeout sites report the last-known window rather than dropping toNone. _compute_occupancy/_usage_componentsstay defensive: non-dict →None; missing/None/non-int subfields →0; thenot isinstance(value, bool)guard excludesbool.- New fields are additive trailing optionals (
Nonedefault);test_existing_positional_construction_still_buildspins non-breaking construction. Field is unconsumed in slice 1, so no runtime regression. except TypeError, ValueError:near the changed code (client.py:740) is pre-existing (not in this diff) and valid Python 3.14 (PEP 758).- CI is green (Unit Tests, Integration Tests, Security Scan all SUCCESS).
Non-blocking observation (no change required)
The added message.usage is not None guard means a top-level turn whose usage is None no longer resets last_assistant_usage — it sticks to the last turn that did report usage. In practice the terminal assistant turn always carries usage, and where every turn lacks it (e.g. usage-free LiteLLM routes) the field stays None → safe reseed, so this only ever biases toward retaining a real window estimate, which is the conservative direction for the reseed decision. Fine as-is; just flagging the behavioural nuance for whoever wires up the consumer in phase 8/10.
Clean slice. The source was already right; the sub-agent edge is now closed before nine downstream slices build on this value.
— Authored by egg
This comment has been minimized.
This comment has been minimized.
|
Automated feedback loop has reached the maximum of 5 rounds. Human review is needed to make further progress on this PR. |
1 similar comment
|
Automated feedback loop has reached the maximum of 5 rounds. Human review is needed to make further progress on this PR. |
0399ef9 to
a9b188e
Compare
This comment has been minimized.
This comment has been minimized.
… conflict in .egg-state/contracts/issue-3200.json Took the base branch's canonical accumulated pipeline state (slices 8/9/10 complete with commits/notes/PR numbers and the full audit log). HEAD carried stale pending/null bookkeeping for those later slices.
Conflict Resolution SummaryResolved merge conflicts with
Details: All 10 conflict regions followed one pattern. This PR's branch (HEAD) carried stale bookkeeping for the later slices — slices 8/9/10 Verified the resolved contract preserves this PR's own state: Verification:
Please review — pre-existing, NOT introduced by this merge: — Authored by egg |
This comment has been minimized.
This comment has been minimized.
There was a problem hiding this comment.
Re-review: [issue-3200][slice-1/10] Token-occupancy capture — merge-only delta, source unchanged ✅
I re-reviewed the current PR head (97ba3df) against my prior approval at 8835a00. The delta since my last review contains no source-code changes.
What changed since 8835a00
The only PR-authored commit in 8835a00..HEAD --not origin/egg/issue-3200/work is the merge commit 97ba3df, whose stated purpose is resolving a conflict in .egg-state/contracts/issue-3200.json. I verified the scope precisely:
- The three code files are byte-identical to my last approval.
git diff 8835a00..97ba3df -- shared/egg_agent/client.py shared/egg_agent/result.py tests/shared/egg_agent/test_client.pyis empty. The occupancy capture logic, the five build sites, the sub-agent filtering, and the test suite I approved at8835a00are unchanged. - All
orchestrator/,docs/,gateway/,integration_tests/,sandbox/changes in the range came from the merged base tip, not this PR.git diff 3ae1f6b..97ba3dfover those trees is empty — HEAD matches the base branch exactly for them. They are out of scope for this slice-1 review (reviewed via their own PRs). - The only PR-unique files vs base are two
.egg-state/brc-history/artifacts — pipeline state managed by the orchestrator, excluded from review per the review rules.
Conflict resolution is correct
The resolution took the base branch's canonical accumulated pipeline state for all conflict regions while preserving slice-1's own bookkeeping. Confirmed in the merged contract: slice-1 → complete | pr 3236, and all 10 slices intact with their commit/PR state. This is an additive state-file progression, not a semantic source conflict — no production logic was in conflict. Per the review rules (.egg-state/ artifacts are orchestrator-managed and skipped), there is nothing blocking here.
Carried-over correctness (unchanged from 8835a00)
The substance I approved still holds: occupancy is sourced from the final per-turn AssistantMessage.usage (never the cumulative ResultMessage.usage); sub-agent turns are filtered via parent_tool_use_id is None; all error/timeout/success build sites thread the value; _compute_occupancy/_usage_components stay defensive (non-dict → None, missing/None/non-int → 0, bool excluded); the new AgentResult fields are additive trailing optionals defaulting to None. Tests pin behaviour against the production path, not hand-built fixtures or self-seeding goldens.
CI
Green on HEAD — Unit Tests, Integration Tests, Security Scan, and all lint suites (Python, Shell, YAML, Docker) SUCCESS; aggregate SUCCESS.
The pre-existing mypy notes flagged in the conflict-resolution summary (client.py:399, 486-487) sit outside the changed regions, are type-annotation issues the review rules explicitly skip, and are not failing CI.
Nothing new to scrutinize and nothing has regressed. Approving.
— Authored by egg
|
egg review completed. View run logs 22 previous review(s) hidden. |
There was a problem hiding this comment.
Contract Re-Verification — PR #3236 (slice-1, AC-1)
Verdict: Approve — no contract violations, no regressions since my last review at 8835a00a.
Scope of this incremental re-review
The only PR-authored commit since 8835a00a is the merge 97ba3df ("Merge origin/egg/issue-3200/work into egg/issue-3200/slice-1"). Verified via git log 8835a00a..HEAD --not origin/egg/issue-3200/work — a single merge commit. Everything else surfaced by a plain two-dot diff is base-branch content pulled in by the merge, not slice-1 work.
What the merge actually changed (the conflict resolution): .egg-state/contracts/issue-3200.json only. It adopted the base branch's canonical accumulated pipeline state — slices 8/9/10 flipped pending → complete with their commits/notes/PR numbers (#3251, #3252) and the corresponding audit-log entries. This is bookkeeping for downstream slices; it does not touch slice-1's deliverable or its AC-1.
Regression check — slice-1 deliverable intact
The three slice-1 source files are byte-identical to my last review (git diff 8835a00a..HEAD empty for each):
shared/egg_agent/result.py—window_occupancy/token_usagefieldsshared/egg_agent/client.py— occupancy capturetests/shared/egg_agent/test_client.py— occupancy tests
The true PR delta vs base (origin/egg/issue-3200/work...HEAD) remains focused: client.py (+91), result.py (+21), test_client.py (+359), plus BRC history artifacts.
AC-1 still holds (re-confirmed)
- task-1-1 (occupancy field):
AgentResult.window_occupancy: int | None = Nonedefaults None, docstring defines occupancy = cache_read + cache_creation + input and explicitly excludes billed input; constructors non-breaking. ✓ - task-1-2 (capture):
_compute_occupancy/_usage_componentscoerce missing/non-int sub-fields to 0; absent/non-dict usage →None(no raise). Occupancy is sourced from the final top-levelAssistantMessage.usage(sub-agent turns filtered viaparent_tool_use_id is None), not the cumulativeResultMessage.usage— a documented correctness improvement over the literal task text (#3200), and threaded into all return sites including the timeout and error paths. ✓ - task-1-3 (tests): coverage present for every required case —
test_full_usage_sums_window_components,test_absent_usage_yields_none_without_raising,test_partial_usage_sums_present_components,test_cache_dominated_turn_includes_cache_read(proves cache_read is counted, not just input), plustest_output_tokens_excluded_from_occupancy,test_subagent_turns_excluded_from_occupancy, andtest_error_result_also_captures_occupancy. ✓
Notes for the human reviewer
- Contract bookkeeping lag (non-blocking, unchanged since last review):
task-1-3status ispendingin the contract even though its tests exist and pass; slice-1 itself isstatus: complete. Cosmetic — the implementation and tests are present. - Criterion marking unavailable this run: the orchestrator is
UNREACHABLE(gateway healthy), soegg-contract verify-criterioncould not be invoked. The contract also carries no top-levelacceptance_criteria[]entries (ACs are embedded per-task), so there is noac-Nto mark; verification above is against the per-task acceptance criteria text.
— Authored by egg
|
egg contract-verification completed. View run logs 22 previous review(s) hidden. |
|
Automated feedback loop has reached the maximum of 5 rounds. Human review is needed to make further progress on this PR. |
…l contract (#3255) (#3261) * fix(ci): stop conflict bot polluting slice-PR history; serve canonical contract (#3255) Slice PRs (egg/<id>/slice-N -> egg/<id>/work) accumulated large numbers of unrelated commits: every later slice's "Persist contract after slice ... completion" commit plus re-stamped copies of the entire refine/plan prefix (observed 9x on PR #3236, 3x/16x on the live slice-1 branch). The file diffs stayed correct, but the commit list was heavily polluted, confusing human and bot reviewers (companion to #3254). Root cause, confirmed against the live issue-3200 branches: the generic on-merge-conflict.yml bot resolves a conflicting PR by merging its *base* into its head. For a slice PR the base is the advancing egg/<id>/work state-branch (the orchestrator commits a contract-persist commit there on every slice completion -- #3117), so each bot merge dragged work's whole lineage into the early slice's history. egg/<id>/work itself is clean and append-only -- the pollution lived entirely on slice branches. The issue's "the reconciler merges work in" framing is a mis-attribution: the orchestrator's stacked-PR reconciler never merges work into running slice branches; this CI bot does. Fix (two halves): 1. on-merge-conflict.yml skips slice PRs. Slice-stack reconciliation is owned by the orchestrator (its stacked-PR reconciler retargets bases; producer agents resolve content conflicts in-pipeline via `git fetch && git merge`), not this generic base-into-head merge bot. The egg/<id>/work -> main context PR is deliberately NOT skipped, so the base PR keeps tracking main. 2. reusable-review.yml overlays the canonical contract from egg/<id>/work into a slice PR's review checkout (working-tree only, never staged/committed/ pushed). Once the bot stops merging work in, a slice branch's contract is frozen at its fork point; contract verification instead reads the live contract from work (the orchestrator's sole-writer branch -- gateway phase_filter #2979). Uses the contents API, not a git fetch+checkout, so no PR-supplied .gitattributes smudge filter can run against the bot token. Adds tests/config/test_slice_pr_history_hygiene.py: structural guards locking in the slice-PR skip, the context-PR exemption, the canonical-contract overlay, and its ordering between PR checkout and the review step. Mechanism-2 lineage duplication (re-stamped refine/plan prefix) is fixed at the source here -- without the work->slice merges the prefix can no longer be re-imported. Any residual rebase-driven duplication is the orthogonal #3146/#3245/#3250 merge-base family. * fix(ci): address review — airtight slice skip + best-effort overlay decode Make the slice-PR conflict-resolution skip airtight by adding it to reusable-conflict-resolve.yml, where the push/schedule and manual-dispatch (workflow_dispatch) entry points converge. The find-step skip only guarded the former; a manual dispatch against a slice PR would otherwise re-pollute its history. The egg/<id>/work -> main context PR is still resolved. Guard the canonical-contract overlay's base64 decode so a bad payload degrades to keeping the PR-branch copy (warning) instead of hard-failing the whole review job under set -euo pipefail, matching the step's best-effort contract. Add structural test coverage for the reusable-workflow slice skip. --------- Co-authored-by: egg-reviewer[bot] <261018737+egg-reviewer[bot]@users.noreply.github.com>
Ground slice-10 (emit-only BRC context-discipline surfaces) in the codebase. Key finding: the slice-1 occupancy field (#3236) and slice-8 reseed signals (#3251) the issue says to derive from are UNMERGED open PRs; origin/main has neither. Registered blocking HITL OQ-1 (substrate dependency, options A-D). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Operator HITL gate resolved the substrate-dependency open question to Option D: emit-only against existing AgentResult fields plus a single adapter seam that degrades to null/zero until slice-1 (#3236) / slice-8 (#3251) merge. No hard dependency, no stacking on egg/issue-3200/*, no vendored substrate. Bake the single-seam direction, emit-only hard scope, and synthetic-sequence AC-3 into the refine analysis. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Capture cumulative window occupancy (cache_read+cache_creation+input) in AgentResult from ResultMessage.usage. Depends on: none. Blocks phases 8 and 10.
Base PR: #3234
What's in this PR
Commits (3):
This slice
Token-occupancy capture (prerequisite, AC-1)
Files affected:
shared/egg_agent/result.pyshared/egg_agent/client.pyshared/egg_agent/tests/Tasks (3) + acceptance criteria
AgentResult(shared/egg_agent/result.py:24-33) with an optional cumulative window-occupancy field (default None, non-breaking). Docstring defines occupancy = cache_read + cache_creation + input and states it is NOT billed/effective input. Optionally retain raw component counts for downstream breakout; the single total is the load-bearing field.shared/egg_agent/client.pystop droppingmessage.usageon the ResultMessage branch (717-751). Read usage, compute occupancy defensively (missing/None sub-fields -> 0), thread it into result_meta and EVERY AgentResult build site in the file (~733/~747/~760/~782/~804/~825). Guard against SDK shapes with no usage.Stack
issue-3200egg/issue-3200/work