fix(core): stop foreign legacy session kind misclassification#1356
fix(core): stop foreign legacy session kind misclassification#1356ChiragArora31 wants to merge 7 commits into
Conversation
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
left a comment
There was a problem hiding this comment.
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.
Made-with: Cursor
…gacy-fallback Co-authored-by: Cursor <cursoragent@cursor.com> # Conflicts: # packages/core/src/session-manager.ts
Greptile SummaryThis PR removes the
Confidence Score: 4/5The 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
|
| 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
Reviews (3): Last reviewed commit: "test(cli): expect report session prefix ..." | Re-trigger Greptile
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
Summary
sessionKindinto canonical lifecycle parsing fromsessionFromMetadataworkerin-memoryRoot cause
When reading metadata,
parseCanonicalLifecycle()could infer orchestrator kind fromsessionId.endsWith("-orchestrator")when no role was present. That fallback misclassified foreign-prefix legacy records in-memory even though on-disk repair no longer stampedrole: orchestrator.What changed
deriveSessionKindFromMetadata()in session manager reconstruction flowsessionKindthroughsessionFromMetadataoptions into lifecycle parsinglifecycle.session.kind === "worker"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.tsCloses #1323.