stacklok / stacklok/mecatl

Session debugger delegation view is missing schedule-fire evidence (dropped by ADR 0299 hardening)

Open
#1,313 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

bug
Dominant language
Go
Stars
152
Forks
16
Avg merge
14h 48m
Merged PRs (30d)
536

Description

Summary

The session debugger's InspectSession delegation view cannot report evidence for scheduled fires. A prior lineage-isolation hardening pass (ADR 0320, "isolate scoped lineage reads") deleted the ev.Schedule branch of internal/adapter/sessiondebug/evidence.go's projectDelegationEvent while adding incarnation-based proof to the Subagent/Parallel/Team branches, and never replaced it. Scheduled-fire delegation rows ("type":"schedule") are silently absent from delegation view output today — there is no code path that produces them at all.

Why it wasn't restored as-is

The pre-hardening code built a "schedule" row directly from session.SchedulePayload with no lineage proof:

if p := ev.Schedule; p != nil {
    return []delegationRow{{Type: "schedule", Event: ev.Type, ScheduleName: safeLine(p.ScheduleName), ScheduleKind: safeLine(p.Kind), Stop: p.Stop, Cause: safeLine(p.Err)}}
}

Restoring this verbatim reintroduces exactly the "unproven event trust" gap TestDelegationHistoryManifestAndLifetimeEvidence guards against (a fabricated/arbitrary event claiming a schedule fire must not be reported as if it were verified lineage evidence).

The other three delegation kinds (Subagent/Parallel/Team) are proof-gated via childFields, which joins the event's claimed (ChildID/MemberSessionID, ChildIncarnation/MemberIncarnation) against the scanned lineage graph and requires the match to be currently RETAINED (ADR 0320's fail-closed isolation — a stale/superseded incarnation of a reused id must never re-attach).

session.SchedulePayload has no incarnation field for the fired session, so it cannot be joined the same way. Doing this correctly needs:

  1. Add a new field to session.SchedulePayload (e.g. SessionIncarnation IncarnationID), matching the ChildIncarnation/MemberIncarnation precedent on SubagentPayload/TeamPayload (comment: "internal durable correlation metadata... deliberately omitted from client/model projections").
  2. Wire the real fired session's incarnation into every SchedulePayload{...} construction site in internal/adapter/scheduler/scheduler.go (there are ~8 sites across fireOne/fireClaimed/FireNow-adjacent code) — the actual incarnation must come from wherever the fired session is created/loaded, which may require plumbing through port.ScheduleFire or the Fire callback's return value.
  3. Add a schedule branch back to projectDelegationEvent using the same childFields-style proof (Kind == session.SessionKindScheduled, Edge == "schedule", matching ScheduleName/OriginSessionID/OriginIncarnation), requiring RETAINED state like the other three kinds.
  4. task api:update + engine/CHANGELOG.md note (Added = minor, per engine/COMPATIBILITY.md) since this touches the exported engine/session API.

Where this was found

Investigating two unrelated CI test failures on main (see #1310, #1311). #1311 updates TestSessionDebuggerCrossBoundaryAcceptance's assertions to match the current (correctly fail-closed, but incomplete) behavior rather than papering over this gap — it does not fix it.

Scope note

Per AGENTS.md's workflow section, this is interface-bearing work (a new exported field + a security-relevant proof path) and should go through the acceptance-plan spine (/to-acceptance-plan), not a quick patch.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with internal/adapter/sessiondebug/evidence.go, session.SchedulePayload, and the SchedulePayload construction sites in internal/adapter/scheduler/scheduler.go; review the existing childFields proof and related debugger tests. Use the acceptance-plan workflow before changing the exported session API. Done means retained, lineage-proven schedule rows appear in InspectSession delegation output, with API metadata and engine/CHANGELOG.md updated.

Written by the indexing model from the issue text.

Assessment

Tech stack
go
Domain
backend, devtools, security
Issue type
Bug
Difficulty
5/5
Estimated time
Over a week
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.