Skip to content

Add session metadata and agent-query application capabilities #20

Closed

Description

@krishna916

Parent epic: #2
Depends on: #19

Context

Relay’s approved agent-integration contract requires persisted session metadata, deterministic session-capture retrieval, and bounded advisory duplicate lookup. These capabilities do not yet exist in the task domain, SQLite repository, or application layer.

This issue owns the shared foundation consumed by MCP and CLI. It deliberately stops below protocol adapters so domain, migration, repository, and application contracts can be reviewed independently.

Goal

Add reviewed application capabilities for agent-created task provenance, session capture retrieval, and lightweight duplicate discovery without introducing MCP or CLI handlers.

Scope

  • add nullable immutable sessionId task metadata
  • add immutable SQL migration and repository mapping
  • enforce agent/human session rules during task creation
  • add exact session-capture repository and application queries
  • add bounded normalized-title duplicate lookup
  • extract shared task runtime composition for HTTP, MCP, and CLI reuse
  • update HTTP task DTOs to include nullable sessionId
  • add domain, migration, repository, application, runtime, and HTTP regression tests

Locked Decisions

  • No session table, session aggregate, timer, completion state, or background process.
  • Agent creation requires createdByName and valid sessionId.
  • Human creation permits only null/omitted sessionId.
  • sessionId is immutable after creation.
  • Session retrieval includes every status and orders by createdAt ASC, id ASC.
  • Duplicate matching is advisory, non-blocking, and normalized-title based.
  • Existing migration 0002_tasks.sql must not be edited; add 0003_task_session_id.sql.
  • Shared runtime composition must continue to use the existing database-path resolver and migrations.

Required Public Application Surface

interface ListSessionCapturesInput {
  readonly sessionId: string;
  readonly limit?: number;
}

interface FindSimilarTasksInput {
  readonly title: string;
  readonly workspace?: string | null;
  readonly limit?: number;
}

interface TaskApplication {
  // existing methods
  listSessionCaptures(input: ListSessionCapturesInput): readonly Task[];
  findSimilar(input: FindSimilarTasksInput): readonly Task[];
}

Out of Scope

  • MCP tool schemas, registration, result mapping, or stdio lifecycle
  • MCP mutation tools
  • CLI commands
  • skills or vendor integration
  • semantic search, FTS, embeddings, or automatic merge
  • packaging or publication

Acceptance Criteria

  • Existing databases migrate without task loss and existing tasks receive sessionId = null.
  • Agent-created tasks require valid session IDs; human-created tasks reject non-null session IDs.
  • Session IDs follow the Define MCP, CLI, session, and mutation contracts #19 format and remain immutable.
  • Session retrieval is exact, deterministic, all-status, and isolated by session.
  • Duplicate lookup is bounded, deterministic, non-archived, and advisory.
  • Repository and application contracts are adapter-neutral.
  • Shared runtime composition is reusable by HTTP, MCP, and CLI.
  • HTTP/UI behaviour remains compatible and full task DTOs include nullable sessionId.
  • No MCP/CLI production handlers are introduced.
  • pnpm verify passes.

Implementation Specification

The earlier issue comment contains both foundation and MCP details. For this revised issue, implement only its domain, persistence, application, runtime, HTTP compatibility, and related test sections. All MCP-specific sections have moved to #26 and are superseded here.

Human Review Gate

Review and merge the migration and public application interfaces before beginning #26, #21, or #22.

Activity

  1. self-assigned this
    on Jul 26, 2026
  2. krishna916 commented on Jul 26, 2026

    @krishna916
    OwnerAuthor

    Authoritative Luna implementation specification — revised after split

    This comment replaces the earlier combined foundation + MCP plan. Issue #20 must not implement any MCP tool, MCP schema, MCP runtime lifecycle, or stdio test. Those responsibilities are exclusively in #26.

    Goal

    Add the adapter-neutral domain, persistence, application, and shared-runtime foundation required by MCP and CLI:

    • immutable nullable sessionId task metadata
    • exact session-capture retrieval
    • bounded advisory duplicate discovery
    • reusable task runtime composition
    • HTTP compatibility for the expanded full-task representation

    Dependencies

    Locked decisions

    • No session table, session aggregate, timer, completion state, or background process.
    • sessionId is caller-generated opaque metadata governed by Define MCP, CLI, session, and mutation contracts #19.
    • AGENT creation requires non-null createdByName and valid non-null sessionId.
    • HUMAN creation permits only omitted/null sessionId; reject a non-null value.
    • sessionId is immutable: it is never part of TaskChanges, edit input, or update SQL.
    • Session retrieval includes all statuses, including DONE and ARCHIVED, ordered by createdAt ASC, id ASC.
    • Duplicate lookup is advisory, normalized-title based, bounded to five, excludes archived tasks, and never creates/updates/deletes tasks.
    • Do not edit applied migration 0002_tasks.sql; add 0003_task_session_id.sql.
    • Runtime composition stays synchronous and continues using database-config.ts, migrations, and SqliteTaskRepository.

    Required files

    Modify

    • src/domain/task/task.ts
    • src/application/tasks/task-repository.ts
    • src/application/tasks/use-cases/create-task.ts
    • src/application/tasks/task-application.ts
    • src/database/tasks/task-row.ts
    • src/database/tasks/sqlite-task-repository.ts
    • src/interfaces/http/main.ts
    • src/interfaces/http/task-dto.ts
    • HTTP/runtime imports affected by extraction
    • existing domain, application, migration, repository, runtime, and HTTP tests

    Create

    • src/database/migrations/0003_task_session_id.sql
    • src/application/tasks/session-id.ts
    • src/application/tasks/title-normalization.ts
    • src/application/tasks/use-cases/list-session-captures.ts
    • src/application/tasks/use-cases/find-similar-tasks.ts
    • src/interfaces/shared/create-task-runtime.ts
    • focused tests for new helpers/runtime where existing suites are not appropriate

    Domain contract

    Add readonly sessionId: string | null to:

    • Task
    • CreateTaskInput
    • RehydrateTaskInput

    Do not add it to TaskChanges.

    Validation:

    trim surrounding whitespace
    length 1..128
    regex ^[A-Za-z0-9._:-]+$
    

    Creation rules:

    AGENT + valid name + valid sessionId => accepted
    AGENT + missing/null sessionId => rejected
    HUMAN + omitted/null sessionId => accepted
    HUMAN + non-null sessionId => rejected

    Rehydration must enforce the same creator/session consistency and reject corrupt persisted rows.

    Migration and repository

    0003_task_session_id.sql must:

    • add session_id TEXT NULL
    • preserve all existing rows with null session IDs
    • add a check for length/allowed characters where SQLite can express it clearly
    • add an index supporting exact retrieval:
    (created_by_type, session_id, created_at ASC, id ASC)

    Do not modify the existing status index.

    Update every explicit task column list, row type, insert binding, and domain mapper. taskToUpdateParameters and update SQL must not write session_id.

    Add repository contracts:

    export interface SessionCaptureQuery {
      readonly sessionId: string;
      readonly limit: number;
    }
    
    export interface SimilarTaskQuery {
      readonly normalizedTitle: string;
      readonly workspace: string | null;
      readonly limit: number;
    }
    
    export interface TaskRepository {
      // existing methods
      listSessionCaptures(query: SessionCaptureQuery): readonly Task[];
      findSimilar(query: SimilarTaskQuery): readonly Task[];
    }

    Repository requirements:

    • exact parameterized session match
    • created_by_type = 'AGENT'
    • all statuses included
    • deterministic created_at ASC, id ASC
    • limits validated before SQL
    • similar query excludes archived rows
    • no dynamic unbounded SQL and no direct adapter filtering after an already-limited query
    • every row maps through taskRowToDomain

    Application contracts

    Extend creation input with optional nullable sessionId and pass it to the domain.

    Add:

    export interface ListSessionCapturesInput {
      readonly sessionId: string;
      readonly limit?: number; // default 100, range 1..100
    }
    
    export interface FindSimilarTasksInput {
      readonly title: string;
      readonly workspace?: string | null;
      readonly limit?: number; // default 5, range 1..5
    }
    
    export interface TaskApplication {
      // existing methods
      listSessionCaptures(input: ListSessionCapturesInput): readonly Task[];
      findSimilar(input: FindSimilarTasksInput): readonly Task[];
    }

    Title normalization is exactly:

    1. trim
    2. lowercase using locale-independent behaviour
    3. collapse internal whitespace to one space
    4. repeatedly remove trailing ., !, or ?, then trim

    Ranking must be deterministic:

    1. exact normalized-title match
    2. same workspace when requested
    3. updatedAt DESC
    4. id ASC

    The application method returns candidates only. It does not create warnings and does not perform capture; #26 composes lookup + create.

    Shared runtime extraction

    Move reusable runtime creation from the HTTP adapter to:

    src/interfaces/shared/create-task-runtime.ts
    

    Expose:

    export interface TaskRuntime {
      readonly taskApplication: TaskApplication;
      readonly close: () => void;
    }
    
    export function createTaskRuntime(
      options?: { readonly databasePath?: string },
    ): TaskRuntime;

    Requirements:

    • create connection through createDatabaseConnection
    • run migrations before repository construction
    • inject SqliteTaskRepository into createTaskApplication
    • close exactly once
    • close a partially opened connection on startup failure
    • no HTTP, MCP, or CLI-specific behaviour

    Update HTTP to consume the shared runtime. A temporary re-export from the old path is acceptable only if it reduces churn and is explicitly marked for later removal.

    HTTP compatibility

    • Full task DTO gains nullable sessionId.
    • Human HTTP creation continues to pass no session ID.
    • HTTP edit schema must not accept sessionId.
    • Existing UI workflow and routes remain otherwise unchanged.

    TDD sequence

    1. Write failing domain tests for creator/session combinations, format boundaries, rehydration, and immutability.
    2. Add migration tests upgrading an existing v2 database with existing tasks.
    3. Implement domain + migration + row mapping + insert/update preservation.
    4. Add repository tests for exact session isolation/order/all statuses and similar lookup bounds/order.
    5. Add failing application tests for session validation, creation rules, query defaults/bounds, normalization, and ranking.
    6. Implement application services and public interfaces.
    7. Extract shared runtime and keep HTTP tests green.
    8. Update HTTP DTO/regression tests.
    9. Update docs/asset validation only where this foundation changes documented task representation.
    10. Run focused and full verification.

    Required tests

    • v2-to-v3 migration preserves existing rows and sets session_id null
    • migration checksum/idempotency rules remain intact
    • session ID lengths 1, 128 accepted; 0/129 and invalid characters rejected
    • AGENT/HUMAN creator-session matrix
    • sessionId cannot be edited or changed by repository update
    • session retrieval includes INBOX, DONE, ARCHIVED; excludes another session and human rows
    • tie-breaking by createdAt, then id
    • normalization across case, whitespace, and trailing punctuation
    • duplicate result limit 1..5 and deterministic ranking
    • archived tasks excluded from similar lookup
    • shared runtime closes once and closes after startup failure
    • HTTP response includes sessionId; create/edit behaviour remains compatible

    Verification

    pnpm test -- tests/unit/domain/task tests/unit/application/tasks
    pnpm test -- tests/integration/database-migrations.test.ts tests/integration/task-repository.test.ts
    pnpm test -- tests/unit/interfaces/shared tests/unit/interfaces/http tests/integration/http-tasks.test.ts
    pnpm format:check
    pnpm lint
    pnpm typecheck
    pnpm test:coverage
    pnpm build
    pnpm validate:assets
    pnpm verify

    Human review gates

    1. Review migration for upgrade safety and immutability.
    2. Review the public repository/application interfaces before adapter work.
    3. Confirm session metadata did not become a session subsystem.
    4. Confirm duplicate lookup remains lightweight and advisory.
    5. Confirm shared runtime is adapter-neutral.
    6. Confirm no MCP/CLI code was added.

    Forbidden scope

    No MCP registration, schemas, mapping, stdio lifecycle, CLI commands, skills, vendor configs, packaging, auth, semantic search, session lifecycle, or background service.

  3. changed the title [-]Implement read and autonomous-capture capabilities through MCP[/-] [+]Add session metadata and agent-query application capabilities[/+] on Jul 26, 2026
  4. krishna916 commented on Jul 26, 2026

    @krishna916
    OwnerAuthor

    Scope split clarification

    The original Luna spec comment combined foundation and MCP work. After review, that scope has been split:

    All MCP-specific sections in the earlier comment are superseded for #20. The domain/persistence/application/runtime sections remain applicable.

  5. linked a pull request that will close this issueFeature/issue 20 session metadata #28on Jul 26, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

No labels
No labels

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions