Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 0 additions & 38 deletions apps/desktop/src/main/__tests__/session-environment-prompt.test.ts

This file was deleted.

34 changes: 14 additions & 20 deletions docs/session-task-ledger-lifecycle.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ inside a Runtime Host Session; it is not an Eval experiment or cell ledger.
## Scope

Maka has a session-scoped task ledger with `task_create`, `task_update`,
`task_list`, `task_get`, `task-events.jsonl`, `tasks.json`, and turn-tail prompt
injection. The implementation keeps lifecycle validation, event replay, storage
`task_list`, `task_get`, `task-events.jsonl`, and `tasks.json`. The implementation
keeps lifecycle validation, event replay, storage
projection, tool access, and recovery classification on one contract.

Non-goals:
Expand All @@ -48,7 +48,7 @@ Every current task has two identifiers:

- `id` is the durable UUID primary key. It is never rewritten.
- `key` is the session-local short reference (`T1`, `T1.1`, and deeper forms)
used in prompts, tools, and UI.
used in model-visible tool results, tools, and UI.

Read and update operations accept either form. Keys are allocated inside the
per-session serialized write queue. A child stores its parent's UUID in
Expand Down Expand Up @@ -125,8 +125,7 @@ The source-backed type includes a conservative `resumeTrust` classifier:
- `untrusted`: ledger, references, or state are corrupt or missing.

The type and pure classifier are source-backed. `resumeTrust` is a system
diagnostic and is not injected into the model-visible task ledger until recovery
logic owns the value.
diagnostic; untrusted tasks are excluded from model-visible tool results.

Recovery/read-model classification uses the conservative classifier:

Expand Down Expand Up @@ -182,27 +181,23 @@ result and supply `completionEvidence`. A failed or cancelled child records the
truthful task outcome; a child waiting for permission leaves the task blocked.
An active task already owned by another child turn cannot be stolen.

## Prompt Budget and Archive
## Model-visible Reads and Archive

The current-turn task tail is capped at 8,000 characters (approximately 2,000
tokens). It renders short keys rather than UUIDs and prioritizes
`in_progress`, `pending`, and `blocked` branches. Ancestors of included active
tasks are retained so hierarchy remains understandable. Up to three recent
terminal tasks are added when budget permits. When tasks are omitted, the tail
reports the omitted count and points the model to `task_list` / `task_get`.
The task ledger is not injected into every model turn. The model reads it on
demand through `task_list` and `task_get`; results render short keys and safe
fielded text rather than copying internal diagnostics.

Terminal tasks receive `endedAt`. They become logically archived after seven
days: storage remains append-only and no task is deleted, while prompt and UI
reads exclude archived terminal tasks. Explicit tool reads may opt back into
them.
days: storage remains append-only and no task is deleted. Callers choose whether
archived terminal tasks are included in a read.

Secret redaction, task-ledger tag stripping, evidence validation, and exclusion
of `resumeTrust=untrusted` tasks apply before model-visible rendering.

## Goal Completion Gate

Ordinary interactive turns never trigger an extra model call because tasks are
unfinished. The turn tail is advisory only.
unfinished.

When an autonomous Goal is active, its external evaluator still decides first.
If the evaluator says achieved or impossible, that terminal decision wins. If
Expand All @@ -218,10 +213,9 @@ the remaining actionable task keys as well.

## Debug and Desktop Read Model

The model-visible task ledger remains compact and omits `resumeTrust`, including
both the turn-tail injection and `task_list` / `task_get` tool results. Debug,
export, and trace/read-model surfaces may include task summaries with
`resumeTrust`, reasons, evidence, and refs.
Model-visible `task_list` / `task_get` results omit `resumeTrust`. Debug, export,
and trace/read-model surfaces may include task summaries with `resumeTrust`,
reasons, evidence, and refs.

Desktop reads the same `Task[]` projection through `tasks:list`. Store changes
emit a signal-only `tasks:changed` event; the renderer reloads instead of
Expand Down
2 changes: 1 addition & 1 deletion docs/windows-test-inventory.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ Total Windows-excluded declarations: **68**
| windows-backend-gap | `packages/runtime-host/src/__tests__/connection-effect-coordinator.test.ts` recovers a durable onboarding intent instead of rolling back a partial publication | `process.platform === 'win32'` |
| windows-backend-gap | `packages/runtime-host/src/__tests__/control-endpoint.test.ts` runtime host control endpoint | `process.platform === 'win32'` |
| windows-backend-gap | `packages/runtime-host/src/__tests__/execution-inspect-uds.test.ts` a live Host serves Interactive inspection over its real endpoint while retaining exclusive ownership | `process.platform === 'win32' ? 'Windows execution Host startup lifecycle' : false` |
| windows-backend-gap | `packages/runtime-host/src/__tests__/execution-model-composition.test.ts` production Host executes current-boundary Bash and refreshes live sandbox context | `process.platform === 'win32' ? 'Managed arbitrary-shell sandboxing is unavailable' : false` |
| windows-backend-gap | `packages/runtime-host/src/__tests__/execution-model-composition.test.ts` production Host executes Bash against the current live sandbox boundary | `process.platform === 'win32' ? 'Managed arbitrary-shell sandboxing is unavailable' : false` |
| windows-backend-gap | `packages/runtime-host/src/__tests__/gitoxide-helper-invocation-internal.test.ts` applies the import deadline and terminates the helper process tree | `process.platform === 'win32'` |
| windows-backend-gap | `packages/runtime-host/src/__tests__/gitoxide-helper-invocation-internal.test.ts` rejects an import response that does not match the requested baseline ref | `process.platform === 'win32'` |
| windows-backend-gap | `packages/runtime-host/src/__tests__/gitoxide-helper-invocation-internal.test.ts` rejects an import response that does not match the requested source HEAD | `process.platform === 'win32'` |
Expand Down
2 changes: 1 addition & 1 deletion docs/work-board-contract.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ The Work Board is a user-owned, local-first surface for deferred work. It is not
execution authority:

- no `task_*` tools, no `task.ledger.query`, and no `workflow_task_ledger_*` reads/writes;
- no model-visible tools and no turn-tail injection;
- no model-visible tools or automatic prompt injection;
- no Goal, AgentRun, RuntimeEvent, or Agent Graph writes;
- execution state is projected at read time, never copied into board storage.

Expand Down
2 changes: 1 addition & 1 deletion docs/work-board-phase1.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ A compact Work Board tab in the session workbar, next to Tasks, with:

- The Desktop main process owns `WorkBoardStore`; the renderer is a read-only
IPC projection that reloads on the `workBoard:changed` signal.
- No Runtime Host involvement, no model-visible tools, no turn-tail injection.
- No Runtime Host involvement, model-visible tools, or automatic prompt injection.
- `linkedSessions` and the linked-session projection remain deferred to Phase 3.

## Why a dedicated store instead of a project file
Expand Down
42 changes: 0 additions & 42 deletions packages/core/src/__tests__/task-ledger.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ import {
isSafeTaskId,
renderSafeTaskLedgerText,
sanitizeTaskLedgerTask,
renderTaskLedgerPromptText,
renderTaskLedgerDebugText,
validateTaskEvidence,
validateTaskUpdate,
Expand Down Expand Up @@ -604,47 +603,6 @@ describe('task ledger events', () => {
});
});

describe('task ledger prompt budget', () => {
test('keeps active ancestors, uses short keys, and reports bounded omissions', () => {
const root: Task = {
id: 'root-uuid',
key: 'T1',
subject: 'root',
status: 'completed',
completionEvidence: 'done',
createdAt: 1,
updatedAt: 2,
endedAt: 2,
};
const child: Task = {
id: 'child-uuid',
key: 'T1.1',
parentId: root.id,
subject: 'active child',
status: 'in_progress',
createdAt: 2,
updatedAt: 3,
};
const extras = Array.from(
{ length: 198 },
(_, index): Task => ({
id: `extra-${index}`,
key: `T${index + 2}`,
subject: `pending ${index} ${'x'.repeat(80)}`,
status: 'pending',
createdAt: index + 3,
updatedAt: index + 3,
}),
);
const rendered = renderTaskLedgerPromptText([root, child, ...extras], 800);
assert.equal(rendered.text.length <= 800, true);
assert.match(rendered.text, /key=T1 .*subject="root"/);
assert.match(rendered.text, /key=T1\.1 .*subject="active child"/);
assert.equal(rendered.text.includes('root-uuid'), false);
assert.equal(rendered.omittedCount > 0, true);
});
});

function event(
type: TaskLedgerEvent['type'],
task: Task,
Expand Down
2 changes: 0 additions & 2 deletions packages/core/src/agent-run.ts
Original file line number Diff line number Diff line change
Expand Up @@ -378,8 +378,6 @@ export const AGENT_RUN_EVENT_TYPES = [
'run_created',
'run_started',
'turn_started',
'sandbox_context_resolved',
'sandbox_context_failed',
'plan_context_resolved',
'plan_submitted',
'plan_execution_started',
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/foreign-session.ts
Original file line number Diff line number Diff line change
Expand Up @@ -644,7 +644,7 @@ export function stripEnvelopeTags(text: string): string {

/**
* Render a digest as an explicitly-untrusted data block for the handoff
* prompt. The envelope wording mirrors the memory/turn-tail discipline:
* prompt. The envelope wording mirrors the untrusted-context discipline:
* contents are reference data, never instructions. `safe()` is the
* authoritative gate every foreign-authored scalar passes through here —
* regardless of how the digest was built — sanitizing (NFC, control/bidi/
Expand Down
Loading