Skip to content

fix(core): stop foreign legacy session kind misclassification#1356

Open
ChiragArora31 wants to merge 7 commits into
AgentWrapper:mainfrom
ChiragArora31:fix/session-kind-legacy-fallback
Open

fix(core): stop foreign legacy session kind misclassification#1356
ChiragArora31 wants to merge 7 commits into
AgentWrapper:mainfrom
ChiragArora31:fix/session-kind-legacy-fallback

Conversation

@ChiragArora31

@ChiragArora31 ChiragArora31 commented Apr 20, 2026

Copy link
Copy Markdown
Contributor

Summary

  • derive session kind during metadata reconstruction using project-scoped orchestrator ID rules
  • pass explicit sessionKind into canonical lifecycle parsing from sessionFromMetadata
  • add regression assertion that foreign-prefix legacy bare orchestrator records remain worker in-memory

Root cause

When reading metadata, parseCanonicalLifecycle() could infer orchestrator kind from sessionId.endsWith("-orchestrator") when no role was present. That fallback misclassified foreign-prefix legacy records in-memory even though on-disk repair no longer stamped role: orchestrator.

What changed

Why this approach

This keeps canonical lifecycle parsing deterministic at read time with project context, without changing persisted metadata format or broad lifecycle behavior.

Testing

  • pnpm --filter @aoagents/ao-core test -- src/__tests__/session-manager/query.test.ts

Closes #1323.

Derive in-memory session kind from project-scoped orchestrator ID rules during metadata reconstruction so foreign-prefix legacy records stay worker-kind unless explicitly marked orchestrator.

Made-with: Cursor

@illegalcall illegalcall 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.

Inline comments below. The helper itself is the right idea, but sessionKind is only threaded through the metadataToSession read path. Several other parse sites (agent-report.ts, recovery/actions.ts, buildUpdatedLifecycle in this same file) still reparse without it, and one of them writes role: "orchestrator" back to disk — which permanently poisons the record because payload.session.kind wins over any override on subsequent reads. Details per line.

Comment thread packages/core/src/session-manager.ts
Comment thread packages/core/src/session-manager.ts Outdated
Comment thread packages/core/src/session-manager.ts Outdated
Comment thread packages/core/src/utils/session-from-metadata.ts Outdated
Comment thread packages/core/src/__tests__/session-manager/query.test.ts
@ChiragArora31 ChiragArora31 requested a review from illegalcall May 1, 2026 11:05
…gacy-fallback

Co-authored-by: Cursor <cursoragent@cursor.com>

# Conflicts:
#	packages/core/src/session-manager.ts
@greptile-apps

greptile-apps Bot commented May 16, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR removes the endsWith(\"-orchestrator\") heuristic from synthesizeCanonicalLifecycle and replaces it with a new deriveSessionKindFromMetadata utility that requires an explicit project-scoped sessionPrefix to classify a session as orchestrator kind. The fix is threaded through session-manager.ts, recovery/actions.ts, and agent-report.ts.

  • Core fix (lifecycle-state.ts): synthesizeCanonicalLifecycle no longer infers orchestrator kind from the session ID suffix, instead relying only on meta[\"role\"] === \"orchestrator\" or an explicit options.sessionKind passed by the caller.
  • New utility (utils/session-kind.ts): deriveSessionKindFromMetadata implements prefix-scoped orchestrator detection (bare legacy {prefix}-orchestrator and numbered {prefix}-orchestrator-{N} forms), short-circuiting to \"worker\" when no prefix is available, preventing foreign-prefix sessions from being misclassified.
  • escapeRegex extraction (utils/regex.ts): The previously-duplicated helper is consolidated into a shared utility module.

Confidence Score: 4/5

The core misclassification is fixed at all actively maintained call sites; two exported functions in metadata.ts still derive session kind without project context.

The fix is correctly implemented across session-manager.ts, recovery/actions.ts, and agent-report.ts. However, readCanonicalLifecycle and updateCanonicalLifecycle in metadata.ts still call deriveSessionKindFromMetadata without sessionPrefix — these are exported as part of the public API and used by lifecycle-transition.ts during polling decisions, meaning a canonical orchestrator session without role metadata can still be read back with kind worker through that path and have its lifecycle durably written with the wrong kind. This gap was flagged in the previous review and remains unaddressed in this PR.

packages/core/src/metadata.ts — readCanonicalLifecycle and updateCanonicalLifecycle lack sessionPrefix and are used by lifecycle-transition.ts

Important Files Changed

Filename Overview
packages/core/src/lifecycle-state.ts Removes the endsWith("-orchestrator") suffix heuristic from synthesizeCanonicalLifecycle; sessionKind is now fully caller-supplied or falls back only to role metadata.
packages/core/src/utils/session-kind.ts New utility implementing prefix-scoped orchestrator detection; correctly handles bare legacy and numbered orchestrator IDs, returns "worker" when no sessionPrefix is provided.
packages/core/src/utils/regex.ts New shared escapeRegex utility extracted from session-manager.ts, eliminating duplication.
packages/core/src/metadata.ts readCanonicalLifecycle and updateCanonicalLifecycle now pass sessionKind but still call deriveSessionKindFromMetadata without sessionPrefix, so canonical orchestrator sessions lacking role metadata are classified as worker through these paths.
packages/core/src/session-manager.ts Replaces inline sessionKind derivation in metadataToSession with deriveSessionKindFromMetadata; threads sessionPrefix into all buildUpdatedLifecycle call sites using project.sessionPrefix.
packages/core/src/recovery/actions.ts buildLifecycleRecoveryPatch now accepts sessionId and sessionPrefix, correctly deriving session kind for recoverSession, cleanupSession, and escalateSession paths.
packages/core/src/agent-report.ts applyAgentReport now accepts an optional sessionPrefix option and passes it to deriveSessionKindFromMetadata at both lifecycle-parsing call sites.
packages/core/src/utils/session-from-metadata.ts Minor field reordering in SessionFromMetadataOptions; sessionKind is placed before status in parseCanonicalLifecycle options. No logic change.
packages/core/src/tests/session-manager/query.test.ts Extends the issue #1048 regression test to assert that in-memory lifecycle.session.kind for a foreign-prefix bare orchestrator record is "worker".
packages/core/src/tests/lifecycle-state.test.ts New test verifies parseCanonicalLifecycle does not infer orchestrator kind from sessionId suffix without an explicit signal.
packages/core/src/tests/agent-report.test.ts New test confirms applyAgentReport with sessionPrefix correctly rejects orchestrator self-reports and leaves no lifecycle blob on disk.
packages/cli/src/commands/report.ts Passes project.sessionPrefix into applyAgentReport options, completing the fix at the CLI layer.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[Read session metadata] --> B{meta role === orchestrator?}
    B -- Yes --> C[kind = orchestrator]
    B -- No --> D{sessionPrefix provided?}
    D -- No --> E[kind = worker]
    D -- Yes --> F{sessionId === prefix-orchestrator?}
    F -- Yes --> C
    F -- No --> G{sessionId matches prefix-orchestrator-N regex?}
    G -- Yes --> C
    G -- No --> E

    C --> H[Pass sessionKind to parseCanonicalLifecycle]
    E --> H
    H --> I[synthesizeCanonicalLifecycle uses options.sessionKind]
    I --> J[CanonicalSessionLifecycle with correct kind]

    style C fill:#d4edda,stroke:#28a745
    style E fill:#fff3cd,stroke:#ffc107
Loading

Reviews (3): Last reviewed commit: "test(cli): expect report session prefix ..." | Re-trigger Greptile

Comment thread packages/core/src/agent-report.ts Outdated
Comment thread packages/core/src/utils/session-kind.ts Outdated
ChiragArora31 and others added 3 commits May 17, 2026 05:20
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
…-1356

# Conflicts:
#	packages/core/src/agent-report.ts
#	packages/core/src/recovery/actions.ts
#	packages/core/src/session-manager.ts
#	packages/core/src/utils/session-from-metadata.ts
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.

In-memory lifecycle.session.kind leaks orchestrator role for foreign-prefix legacy records

2 participants