Skip to content

Commit de6054e

Browse files
feat(core,storage,cli): evidence pointers and staleness flags for foreign session handoff
Follow-up to #1057 (parts 1+2 merged as #1208/#1221), implementing the compatible half of ofekron's post-merge design feedback: the handoff should carry claims with evidence pointers and confidence flags, not just a summary. - ForeignSessionDigest gains `transcriptPath` (the evidence pointer for the whole digest) and `filesTouched` entries carry `lastEventAtMs` — the source event's own timestamp. Timestamps were chosen over transcript line offsets deliberately: large transcripts are read as a bounded TAIL window, where line numbers would be window-relative and silently wrong. - New handoff-time staleness check: @maka/storage probes the CURRENT repo state (cwd existence, branch via .git/HEAD — worktree gitdir files followed one level, no git spawn — and per-touched-file mtimes), and pure core assessment turns mismatches into typed flags (cwd_missing / branch_changed / files_changed / files_missing). Per-file mtimes compare against each touch's own event timestamp, falling back to the session clock. - The report renders as a Maka-authored <repo-state-check> block between the instruction and the untrusted envelope. An empty flag list renders an explicit all-clear (a receiving agent must be able to tell "checked and clean" from "never checked"), and stripEnvelopeTags now covers the new tag so a hostile path cannot forge maka-verified content. Probe failure degrades to the unchecked handoff shape. - Deliberately NOT implemented from the feedback: carrying "checks run and observed results" forward — tool outputs stay excluded per the #1057 safety contract; the staleness flags provide the confidence signal without trusting the transcript's account of the world. Tests: core 1183/1183 (evidence semantics, every flag kind, all-clear rendering, envelope-forgery defense, handoff composition), storage 530/530 (probe on real dirs: branch, worktree gitdir, detached HEAD, missing cwd), cli 652/652 (handoff carries the flagged report end-to-end through the picker import).
1 parent 9d9a47b commit de6054e

7 files changed

Lines changed: 392 additions & 26 deletions

File tree

packages/cli/src/__tests__/pi-tui-runner.test.ts

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5819,6 +5819,10 @@ describe('Maka Pi TUI runner', () => {
58195819
updatedAtMs: Date.now(),
58205820
transcriptPath: '/home/u/.claude/projects/-repo/fabc.jsonl',
58215821
};
5822+
// A REAL directory as the digest cwd so the handoff-time repo probe runs
5823+
// deterministically: the cwd exists, and the single touched file does
5824+
// not — the staleness report must flag it.
5825+
const digestCwd = await mkdtemp(join(tmpdir(), 'maka-foreign-handoff-'));
58225826
let readDigestCalls = 0;
58235827
const foreignSessions = {
58245828
availableSources: async () => ['claude-code' as const],
@@ -5829,11 +5833,12 @@ describe('Maka Pi TUI runner', () => {
58295833
source: 'claude-code' as const,
58305834
id: 'fabc',
58315835
title: 'Prior parser work',
5832-
cwd: '/repo',
5836+
cwd: digestCwd,
58335837
updatedAtMs: summary.updatedAtMs,
5838+
transcriptPath: summary.transcriptPath,
58345839
userMessages: ['重构解析器'],
58355840
assistantTexts: ['已修复并补测试'],
5836-
filesTouched: ['/repo/parser.ts'],
5841+
filesTouched: [{ path: 'parser.ts' }],
58375842
warnings: [],
58385843
};
58395844
},
@@ -5867,6 +5872,11 @@ describe('Maka Pi TUI runner', () => {
58675872
assert.match(driver.prompts[0]!, /<foreign-session-digest>/);
58685873
assert.match(driver.prompts[0]!, /untrusted reference DATA/);
58695874
assert.match(driver.prompts[0]!, //);
5875+
// The Maka-verified repo state check ran: cwd exists, the touched file
5876+
// does not — the handoff carries the mismatch as an explicit flag.
5877+
assert.match(driver.prompts[0]!, /<repo-state-check maka-verified="true">/);
5878+
assert.match(driver.prompts[0]!, /\[files_missing\].*parser\.ts/);
5879+
assert.match(driver.prompts[0]!, /source_transcript="[^\n]*fabc\.jsonl"/);
58705880

58715881
exitMaka(terminal);
58725882
await Promise.race([

packages/cli/src/pi-tui-runner.ts

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,12 +27,13 @@ import {
2727
type ShellRunUpdate,
2828
} from '@maka/core';
2929
import {
30+
assessForeignSessionStaleness,
3031
buildForeignSessionHandoffMessage,
3132
foreignSessionHandoffDisplayText,
3233
foreignSourceLabel,
3334
type ForeignSessionSummary,
3435
} from '@maka/core/foreign-session';
35-
import type { ForeignSessionStore } from '@maka/storage';
36+
import { probeForeignSessionRepoState, type ForeignSessionStore } from '@maka/storage';
3637
import type { GoalTurnOutcome, SessionActivityLease } from '@maka/runtime';
3738
import type { ModelChoice } from './connection-target.js';
3839
import {
@@ -1784,13 +1785,22 @@ export async function runMakaPiTui(input: MakaPiTuiInput): Promise<void> {
17841785
let handedOff = false;
17851786
try {
17861787
const digest = await input.foreignSessions.readDigest(summary);
1788+
// #1057 follow-up: probe the CURRENT repo state (cwd / branch / touched-
1789+
// file mtimes) and hand the model Maka-verified staleness flags instead
1790+
// of leaving it to trust the transcript's account of the world. The
1791+
// probe is best-effort — a probe failure downgrades the handoff to the
1792+
// unchecked shape rather than blocking the import.
1793+
const staleness = await probeForeignSessionRepoState(digest).then(
1794+
(probe) => assessForeignSessionStaleness(digest, probe),
1795+
() => undefined,
1796+
);
17871797
if (closed) return;
17881798
newSession();
17891799
void runAgentTurn({
17901800
kind: 'external',
17911801
prompt: foreignSessionHandoffDisplayText(digest),
17921802
sessionId: input.driver.getSessionId(),
1793-
sendText: buildForeignSessionHandoffMessage(digest),
1803+
sendText: buildForeignSessionHandoffMessage(digest, staleness),
17941804
});
17951805
handedOff = true;
17961806
} catch (error) {
7.38 KB
Binary file not shown.

0 commit comments

Comments
 (0)