Documentation
¶
Overview ¶
Package session bridges INTERACTIVE crush sessions into the same close-out pipeline pool agents get. Pool work is reviewed and reported on because the journal sees its completions; interactive sessions leave no task trail, so their commits could silently skip the second opinion. The bridge closes that gap: `tq session begin` records the session's opening in the journal, and `tq session close` attributes the session's commits (a `Crush-Session: <id>` git footer written by the committer), then directly enqueues ONE review task over the attributed commit range and ONE done-prompt status task. Both ride the ordinary pool: they are ordinary "review"/"status" tasks, drained by whichever agent-capable pool shares the database, dedup-keyed so re-closing a session never duplicates work.
Close is deliberately enqueue-only (the crush SessionEnd hook budget is ~2s): git attribution scan, two idempotent enqueues, one journal fact. The pool does everything else.
Loop safety is structural: session facts carry the synthetic "session:<id>" task identity, which no task row ever uses, so sweepers and workers cannot mistake session lifecycle for task state; the minted review is type "review" and the status task type "status", both exempt from re-review by the sweeper's agent-only rule.
Index ¶
Constants ¶
const Trailer = "Crush-Session"
Trailer is the git-footer key that attributes a commit to an interactive session: committers end their commit message with `Crush-Session: <id>` (same convention as the Task-Queue-ID footer pool agents write). Close attributes exactly the commits whose trailer value equals the session id.
Variables ¶
This section is empty.
Functions ¶
func Begin ¶
Begin records the session's opening as a session.opened fact. Refusing a double begin keeps one open epoch per id: begin, work, close — re-running begin for an already-open session is a mistake, not idempotent noise.
func SyntheticTaskID ¶
SyntheticTaskID returns the session's task-ID-shaped lineage key: the TaskID on session facts and the ReviewedTask / Completed.TaskID lineage in the minted review and status payloads. It is namespaced so it can never collide with a real task ID ("session:" is not a hex ULID prefix).
Types ¶
type CloseDetail ¶
type CloseDetail struct {
SessionID string `json:"session_id"`
Repo string `json:"repo"`
Project string `json:"project,omitempty"`
Summary string `json:"summary,omitempty"`
Commits []Commit `json:"commits"`
ReviewTask string `json:"review_task,omitempty"`
StatusTask string `json:"status_task,omitempty"`
}
CloseDetail is the session.closed fact's detail: what the session committed (as far as attribution can see) and what close minted.
type CloseInput ¶
type CloseInput struct {
// ID is the interactive session's id (CRUSH_SESSION_ID). Required.
ID string
// Repo is the absolute repository path the session worked in. Required.
Repo string
// Project is the queue project the minted tasks belong to (convention:
// the repo directory's base name).
Project string
// Summary is the operator's one-paragraph account of what the session
// did; it becomes the review's bar and the status entry's item. Empty
// falls back to a default text.
Summary string
// AllowDirty mirrors the pool's --allow-dirty stance into the minted
// payloads' RequireClean: a multi-agent repo is effectively always
// dirty, and a clean-tree-required task there requeues forever.
AllowDirty bool
}
CloseInput carries one Close invocation's parameters.
type CloseResult ¶
type CloseResult struct {
// Commits are the session-attributed commits, oldest first.
Commits []Commit
// ReviewTask / StatusTask are the minted tasks; zero TaskIDs when no
// commits were attributed (nothing minted).
ReviewTask task.Task
StatusTask task.Task
// ReviewFresh / StatusFresh are false when the enqueue hit the dedup
// key (the task already existed from an earlier close of this session).
ReviewFresh bool
StatusFresh bool
}
CloseResult reports what Close recorded and minted.
func Close ¶
func Close(ctx context.Context, s Store, scanner GitScanner, in CloseInput) (CloseResult, error)
Close attributes the session's commits, records the session.closed fact, and directly enqueues the close-out: ONE review over the attributed range and ONE status report, both idempotent by dedup key. A session with no attributed commits records only the fact — there is nothing to review and nothing to report.
type GitLogScanner ¶
type GitLogScanner struct {
// Bin is the git binary; empty means "git" from PATH.
Bin string
}
GitLogScanner attributes commits by scanning `git log` for the footer trailer. Commits come back oldest first. Requires git >= 2.15 (%(trailers) format); every supported environment clears that floor by years.
func (GitLogScanner) CommitsByTrailer ¶
func (s GitLogScanner) CommitsByTrailer(ctx context.Context, repo, key, value string) ([]Commit, error)
CommitsByTrailer implements GitScanner. A repository without any commit yet (unborn HEAD) attributes nothing — that is an empty session, not an error.
type GitScanner ¶
type GitScanner interface {
CommitsByTrailer(ctx context.Context, repo, key, value string) ([]Commit, error)
}
GitScanner attributes commits: which commits in repo carry the git footer `key: value`. The interface keeps Close hermetic to test; GitLogScanner is the real implementation.
type GitScannerFunc ¶
GitScannerFunc adapts a function to GitScanner.
func (GitScannerFunc) CommitsByTrailer ¶
func (f GitScannerFunc) CommitsByTrailer(ctx context.Context, repo, key, value string) ([]Commit, error)
CommitsByTrailer implements GitScanner.
type OpenDetail ¶
type OpenDetail struct {
SessionID string `json:"session_id"`
Repo string `json:"repo"`
Project string `json:"project,omitempty"`
}
OpenDetail is the session.opened fact's detail.
type Store ¶
type Store interface {
Enqueue(ctx context.Context, n task.New) (task.Task, error)
AppendFact(ctx context.Context, f journal.Fact) error
FactsForTask(ctx context.Context, id string, limit int) ([]journal.Fact, error)
}
Store is the bridge's view of the queue core: mint tasks, append the session's lifecycle facts, and read one identity's facts (the double-begin guard).