fix(daemon): recognize Claude effort in identity proof (#681)

A Claude seat launched with --effort now passes exact identity proof. Both argv readers in native-process-lineage.ts skip --effort <value> and --effort=<value> like the other launch options, so clear-attention can re-verify a shell-wrapped seat whose binding declares effort, and delivery no longer warns about unverified identity for it. Unknown arguments still give no positive proof. Three test rows cover the separated and equals forms and an unknown-flag control through strict proof and delivery.

Refs #197
This commit is contained in:
Mike Schwarz authored and GitHub committed 2026-10-04 00:47:35 -07:00
1 parent 07da904fa7
commit 6bdbed2b2e
2 files changed
+15 -5

No files matched your search

@@ -95,8 +95,8 @@ function claudeSessionToken(args: string[]): string | null {
for (let index = 0; index < args.length; index += 1) {
const arg = args[index]!;
if (index === 0 && /^\(\d+\.\d+\.\d+[^)]*\)$/.test(arg)) continue;
if (["--permission-mode", "--model", "--name"].includes(arg)) { index += 1; continue; }
if (/^--(?:permission-mode|model|name)=/.test(arg) || arg === "--dangerously-skip-permissions") continue;
if (["--permission-mode", "--model", "--name", "--effort"].includes(arg)) { index += 1; continue; }
if (/^--(?:permission-mode|model|name|effort)=/.test(arg) || arg === "--dangerously-skip-permissions") continue;
const identity = arg.match(/^--(?:session-id|resume)(?:=(.*))?$/);
if (!identity) return null; // Unknown argv is not positive identity proof.
const value = identity[1] ?? args[++index];
@@ -115,12 +115,12 @@ function claudeSessionIdentity(args: string[]): string | null | { unparsed: true
for (let index = 0; index < args.length; index += 1) {
const arg = args[index]!;
if (index === 0 && /^\(\d+\.\d+\.\d+[^)]*\)$/.test(arg)) continue;
if (["--permission-mode", "--model", "--name", "--settings"].includes(arg)) {
if (["--permission-mode", "--model", "--name", "--settings", "--effort"].includes(arg)) {
const value = args[++index];
if (!value || value.startsWith("-")) return unparsed;
continue;
}
if (/^--(?:permission-mode|model|name|settings)=/.test(arg) || arg === "--dangerously-skip-permissions") continue;
if (/^--(?:permission-mode|model|name|settings|effort)=/.test(arg) || arg === "--dangerously-skip-permissions") continue;
const identity = arg.match(/^--(?:session-id|resume)(?:=(.*))?$/);
if (!identity) return unparsed; // Unknown argv is not positive identity proof.
const value = identity[1] ?? args[++index];
@@ -24,6 +24,7 @@ const modes = [
"launcher-shim-match", "launcher-shim-match-after", "launcher-shim-child-differs",
"launcher-shim-child-differs-after", "launcher-shim-child-unparsed",
"launcher-shim-shims-differ", "launcher-shim-child-two-sessions", "settings-single",
"effort-separated", "effort-equals", "unknown-value-flag",
];
// The real process behind a spawning shim carries its own argv.
const shimChild: Record<string, string> = {
@@ -60,6 +61,12 @@ it.each(modes)("selector and ordinary transport: %s", async (mode) => {
command: `${executable} --permission-mode auto ${mode === "settings-single" ? "--settings /fixture/settings.json " : ""}${mode === "missing-token" ? "" : `--session-id ${mode.startsWith("wrong-token") || mode === "launcher-shim-shims-differ" ? "different" : token}`} --name ${name}`, startedAt },
]),
];
const extraFlag: Record<string, string> = {
"effort-separated": "--effort high",
"effort-equals": "--effort=high",
"unknown-value-flag": "--unrecognised-flag high",
};
if (extraFlag[mode]) rows[2]!.command += ` ${extraFlag[mode]}`;
// The shell still owns the terminal; these children are in background groups.
if (mode === "bare-shell-helper" || mode === "bare-shell-job") {
rows.push({ pid: 103, ppid: 100, pgid: 103, tpgid: 100,
@@ -123,6 +130,7 @@ it.each(modes)("selector and ordinary transport: %s", async (mode) => {
"launcher-shim-match", "launcher-shim-match-after", "launcher-shim-child-unparsed",
"launcher-shim-child-two-sessions", "settings-single",
"wrong-token", "wrong-token-post-read-error", "wrong-token-post-read-empty", "launcher-shim-shims-differ",
"effort-separated", "effort-equals", "unknown-value-flag",
].includes(mode);
if (bare) expect({ ok: sent.ok, calls }).toEqual({ ok: false, calls: [] });
expect(sent.ok).toBe(expectedSend);
@@ -131,8 +139,9 @@ it.each(modes)("selector and ordinary transport: %s", async (mode) => {
expect(observation !== null).toBe([
"npm-name", "versioned", "pane-command-unavailable", "versioned-direct-pane", "missing-metadata",
"ambiguous-pane", "changed-binding", "onboarding", "changed-after-paste",
"effort-separated", "effort-equals",
].includes(mode));
if (expectedSend && ["unavailable", "unknown-both", "missing-token", "missing-metadata", "background", "other-semver", "versioned-argv-only", "versioned-comm-only", "launcher-shim", "launcher-shim-child-unparsed", "launcher-shim-child-two-sessions"].includes(mode)) {
if (expectedSend && ["unavailable", "unknown-both", "missing-token", "missing-metadata", "background", "other-semver", "versioned-argv-only", "versioned-comm-only", "launcher-shim", "launcher-shim-child-unparsed", "launcher-shim-child-two-sessions", "unknown-value-flag"].includes(mode)) {
expect(sent.warning).toContain("without verified native identity");
}
// Static launch tokens alone cannot prove a different current recipient after
@@ -142,6 +151,7 @@ it.each(modes)("selector and ordinary transport: %s", async (mode) => {
}
// --settings is delivery-only: the strict selector above still rejects it (observation === null).
if (mode.startsWith("launcher-shim-match") || mode === "settings-single") expect(sent.warning ?? "").not.toContain("without verified native identity");
if (mode.startsWith("effort-")) expect(sent.warning ?? "").not.toContain("without verified native identity");
if (mode.startsWith("launcher-shim-child-differs")) expect(sent.error).toContain("name different conversations");
if (mode === "launcher-shim-mixed-token") expect(sent.error).toContain("name different conversations");
// Two children of one shim are two runtimes, not a chain.