Skip to content

Environment and compaction hygiene from the #48 and #57 reviews (invariants, guards, consistency, tests, docs) #54

Open

Description

@kakasplatt

Non-blocking follow-ups from the #48 and #57 reviews. They make implicit invariants explicit, align leftover predicates, record design decisions and close test and doc gaps. Today none of them changes behavior. Helper dedupes (pathIdentity, ID sources, turn_id reads) and the fixes to propose upstream are tracked in #50.

Work items


Preserved original reports

Original report: #54 — Make the compaction-only calendar delta channel explicit in thread-environment

Finding

Found in the #48 review. The code is from upstream miuuyy#884 plus the fork's #28 resolution in #48.

In src/adapters/chatgpt-web/thread-environment.ts (resolve recovery path), the calendar delta now reaches the root logic through two channels:

const calendarDelta = hasCurrentContext && !currentCompaction
  ? extractChatGptCalendarEnvironmentDelta(parsed) : undefined;
...
const resolvedCalendarDelta = calendarDelta ?? currentClaim?.calendarDelta;
  • The local calendarDelta is gated by !currentCompaction.
  • currentClaim?.calendarDelta is not gated. Today only extractChatGptContinuationEnvironmentClaim sets it, and that runs only when currentCompaction is true.

That makes the code safe today: conflictingAuthorityFields(currentClaim, rolloutEnvironment) bounds the resulting roots to the claim's own roots, and #48's tests pin that. But the invariant is implicit. A future change that makes another claim source carry calendarDelta would apply the #28 context-root adoption, contextRoots, without the !currentCompaction gate, and no test would notice.

Expected

Make the invariant explicit, for example:

  • type calendarDelta as present only on the continuation claim (a separate return type), or
  • derive resolvedCalendarDelta explicitly (currentCompaction ? currentClaim?.calendarDelta : calendarDelta), with a test that a steering or native-compaction claim carrying calendarDelta is ignored or rejected.

Coordinate with upstream: the two-channel shape comes from miuuyy#884.

Original report: #58 — Follow-up from PR #57 review: root order, ..: segments and C0 controls

Only the Guard limits and Not an issue sections of #58 belong here. Its Behavior section moved to #52.

Follow-up items from the final review of #57 (#29). The reviewer left them out of scope, and they are not recorded in #29 or #50.

Behavior

  • Root order in a midnight delta versus the broker. This predates fix(environment): keep established roots and spelling across midnight deltas (#29) #57.
    • calendarContextRoots (src/adapters/chatgpt-web/thread-environment.ts, the latest branch) compares the delta roots with the native roots as sets, then returns the delta's list in the delta's order.
    • Scenario: a full-access rollout that omits workspace_roots, a turn that started with roots [cwd, sibling], and a midnight delta that repeats them as [sibling, cwd].
    • The resolved environment then differs from the pinned turn-start environment only in order. TurnBroker.updateEnvironment compares environmentIdentity with JSON, so it aborts with "environment changed during an active ChatGPT tool loop".
    • This is the same family as the spelling issue that fix(environment): keep established roots and spelling across midnight deltas (#29) #57 fixed with preferSpelling.
    • A possible fix: when the cached entry has the same set of identities, return it in the cached order and spelling.

Guard limits

Not an issue (recorded for completeness)

  • ... and .. (trailing dots or spaces) count as inside the root. Win32 strips trailing dots and spaces from the last segment, so these names resolve to the root itself.
Original report: #59 — Follow-up from PR #57 second review: visualization check, spelling precedence, double peek

Findings from the second full review of #57 that are not tracked elsewhere. The review's other findings are either fixed in #57 (8b67b20, the broker's ..notes cwd check) or already tracked: the <agent name> form in #29, and the duplicated containment helpers in #50.

Consistency

Design decision to record

  • Cached spelling wins over a full environment claim in the same request.
    • Location: thread-environment.ts, the preferSpelling block after calendarContextRoots.
    • On a calendar-delta turn, a cached entry's spelling replaces the spelling of paths with the same identity, even when the request also carries a full environment (compaction continuation or steering).
    • Current rationale: the broker compares later environments with the pinned turn-start environment, which is the cached one, by exact JSON. Preferring the cache keeps the tool loop alive. Identities, and therefore authority, are unchanged.
    • Confirm: a compaction continuation that starts a new broker registration would pin the request's spelling instead, so it should not get the cached one. Check whether any path re-registers with this resolved environment and could expect the request's own spelling.

Minor efficiency and readability

  • peek() runs twice on a rootless calendar-delta turn. It runs once inside calendarContextRoots and once in the spelling block, with the same lookup and TTL check.
    • The cost is negligible.
    • Reading the entry once and passing it to calendarContextRoots would make the cache dependence of both steps explicit.
Original report: #51 — Tests: broaden compaction plus midnight coverage from the #48 review

Finding

The #48 reviews left minor test-coverage gaps in the compaction plus midnight tests in tests/environment.test.ts (added in 2e3fc06 and c25bf4b). None blocks the merge: the security properties are pinned, as mutation checks confirmed.

Tests

Docs

docs/superpowers/plans/2026-10-22-issue46-upstream-sync.md has rationale the execution corrected; it should be annotated or amended:

  • Task 2 step 1 asks for delta roots "that the preamble does not list". That is impossible by design (conflictingAuthorityFields).
  • Task 2 step 2 expects test A to fail under upstream's strict block because of the relaxation. It fails only on Windows, because of the case bug.
  • Task 3 step 1 assumes bun run verify is green. It is red because of the root bun audit advisory.
Original report: #53 — server.ts compaction comment still says both representations are authenticated

Finding

Found in the #48 review, in code brought in from upstream (4ad190f "Preserve agent-only child compaction without a nonexistent human alias", 59b5b0f).

In src/server.ts (~line 719-729), the comment above the compaction checkpoint still says:

v1 installs the bounded user-message output, whereas v2 retains the original source. Authenticate both exact producer-defined representations, never arbitrary rewrites.

The code now calls findChatGptCompactionSourceRevision for the v1 representation. When that returns undefined (a child with only parent instructions and contextual items, no human source), rememberCompactionContinuation receives only [source], so only one representation is authenticated in that case.

The behavior looks intentional: upstream added it so agent-only child compactions do not need a nonexistent human alias. The comment no longer describes it, though, and nothing states that skipping the v1 alias is the intended, safe outcome.

Expected

  • Update the comment to state when the v1 alias is omitted and why that is safe.
  • Optionally, add an assertion or test that the single-alias checkpoint is only produced for the agent-only child case.
  • If upstream changes this comment, take their wording on the next sync instead, to avoid a conflict.

Activity

  1. changed the title [-]Make the compaction-only calendar delta channel explicit in thread-environment[/-] [+]Environment and compaction hygiene from the #48 and #57 reviews (invariants, guards, consistency, tests, docs)[/+] on Oct 23, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions