@lannguyensi/harness 0.32.0 → 0.34.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. package/CHANGELOG.md +40 -0
  2. package/README.md +8 -5
  3. package/dist/cli/adopt/index.d.ts +7 -0
  4. package/dist/cli/adopt/index.js +10 -0
  5. package/dist/cli/adopt/index.js.map +1 -1
  6. package/dist/cli/apply/apply.d.ts +14 -0
  7. package/dist/cli/apply/apply.js +21 -6
  8. package/dist/cli/apply/apply.js.map +1 -1
  9. package/dist/cli/approve/branch-protection.d.ts +69 -0
  10. package/dist/cli/approve/branch-protection.js +157 -0
  11. package/dist/cli/approve/branch-protection.js.map +1 -0
  12. package/dist/cli/approve/understanding.d.ts +12 -0
  13. package/dist/cli/approve/understanding.js +50 -3
  14. package/dist/cli/approve/understanding.js.map +1 -1
  15. package/dist/cli/gc/index.d.ts +47 -0
  16. package/dist/cli/gc/index.js +148 -0
  17. package/dist/cli/gc/index.js.map +1 -0
  18. package/dist/cli/index.js +174 -14
  19. package/dist/cli/index.js.map +1 -1
  20. package/dist/cli/init/composer.js +11 -5
  21. package/dist/cli/init/composer.js.map +1 -1
  22. package/dist/cli/init/profiles.d.ts +2 -2
  23. package/dist/cli/init/profiles.js +2 -2
  24. package/dist/cli/init/templates.d.ts +1 -1
  25. package/dist/cli/init/templates.js +8 -4
  26. package/dist/cli/init/templates.js.map +1 -1
  27. package/dist/cli/pack/hook-branch-protection.d.ts +8 -0
  28. package/dist/cli/pack/hook-branch-protection.js +59 -15
  29. package/dist/cli/pack/hook-branch-protection.js.map +1 -1
  30. package/dist/cli/pack/hook-pre-tool-use.js +31 -2
  31. package/dist/cli/pack/hook-pre-tool-use.js.map +1 -1
  32. package/dist/cli/pack/hook-solution-acceptance.d.ts +2 -0
  33. package/dist/cli/pack/hook-solution-acceptance.js +24 -10
  34. package/dist/cli/pack/hook-solution-acceptance.js.map +1 -1
  35. package/dist/cli/pack/read-only-bash.js +127 -4
  36. package/dist/cli/pack/read-only-bash.js.map +1 -1
  37. package/dist/cli/uninstall/index.d.ts +24 -5
  38. package/dist/cli/uninstall/index.js +73 -6
  39. package/dist/cli/uninstall/index.js.map +1 -1
  40. package/dist/policy-packs/builtin/branch-protection-runtime.d.ts +47 -6
  41. package/dist/policy-packs/builtin/branch-protection-runtime.js +53 -6
  42. package/dist/policy-packs/builtin/branch-protection-runtime.js.map +1 -1
  43. package/dist/policy-packs/builtin/branch-protection.js +24 -14
  44. package/dist/policy-packs/builtin/branch-protection.js.map +1 -1
  45. package/dist/policy-packs/builtin/solution-acceptance-runtime.d.ts +18 -0
  46. package/dist/policy-packs/builtin/solution-acceptance-runtime.js +32 -0
  47. package/dist/policy-packs/builtin/solution-acceptance-runtime.js.map +1 -1
  48. package/dist/policy-packs/builtin/understanding-before-execution-runtime.d.ts +82 -10
  49. package/dist/policy-packs/builtin/understanding-before-execution-runtime.js +88 -22
  50. package/dist/policy-packs/builtin/understanding-before-execution-runtime.js.map +1 -1
  51. package/dist/policy-packs/builtin/understanding-before-execution.d.ts +11 -0
  52. package/dist/policy-packs/builtin/understanding-before-execution.js +15 -0
  53. package/dist/policy-packs/builtin/understanding-before-execution.js.map +1 -1
  54. package/package.json +3 -3
@@ -1,4 +1,5 @@
1
1
  import type { PolicyPack } from "../../schema/index.js";
2
+ import { type ApprovalMarker, type CheckApprovalMarkerOptions, type MarkerCheck } from "./understanding-before-execution-runtime.js";
2
3
  export declare const PACK_NAME = "branch-protection";
3
4
  /**
4
5
  * Ledger tag written by the producer when the current branch is NOT in
@@ -8,14 +9,54 @@ export declare const PACK_NAME = "branch-protection";
8
9
  */
9
10
  export declare const NON_PROTECTED_TAG_PREFIX = "branch:non-protected";
10
11
  /**
11
- * Operator escape-hatch tag. Set via `mcp__agent-grounding__ledger_add`
12
- * (Bash is gated by this very pack, so a shell-based override would be
13
- * unreachable). The blocker substring-matches this prefix; the trailing
14
- * `:<reason>` is a free-form note the operator types so a later audit
15
- * can read WHY the override fired (e.g. `branch-protection-ack:hotfix
16
- * for prod`).
12
+ * Operator escape-hatch tag, kept as a best-effort AUDIT echo only.
13
+ *
14
+ * SECURITY (audit finding #39): this tag is NO LONGER a trusted override
15
+ * signal. The agent has direct `mcp__agent-grounding__ledger_add` access,
16
+ * so it could self-write `branch-protection-ack:<anything>` and bless its
17
+ * own protected-branch edit — exactly the self-approval backdoor the
18
+ * understanding gate closed in agent-tasks/88ca4bb3 by moving the
19
+ * canonical approval to a filesystem marker. The blocker now consults the
20
+ * operator-only marker file (see `checkBranchProtectionMarker` below); the
21
+ * `harness approve branch-protection` verb still records this ledger tag
22
+ * so `harness audit` / forensics keep a trail, but its presence alone
23
+ * never satisfies the gate. The trailing `:<reason>` stays free-form.
17
24
  */
18
25
  export declare const ACK_TAG_PREFIX = "branch-protection-ack";
26
+ /**
27
+ * Marker-name namespace for an operator-written branch-protection
28
+ * override. The marker lives in the shared `.approvals/` directory under
29
+ * `harness.generated/` (the same directory the understanding gate uses),
30
+ * prefixed so it can never be confused with an understanding-gate session
31
+ * marker (`.approvals/<sessionId>`) or a task marker (`.approvals/task-<id>`):
32
+ * Claude Code / Codex session ids are UUIDs and never start with this
33
+ * literal, so the three namespaces stay disjoint.
34
+ *
35
+ * Why a marker and not the `branch-protection-ack` ledger tag: only a
36
+ * process the operator launched (their `!`-shell or any un-hooked
37
+ * terminal) can write under `harness.generated/` — Edit / Write / Bash
38
+ * are all gated, and the configured MCP servers expose no filesystem
39
+ * write. So the marker is the canonical override signal; the ledger row
40
+ * is a best-effort audit echo only.
41
+ */
42
+ export declare const BRANCH_PROTECTION_MARKER_PREFIX = "branch-protection-";
43
+ /** Marker filename (inside `.approvals/`) for a session's branch-protection override. */
44
+ export declare function branchProtectionMarkerName(sessionId: string): string;
45
+ /**
46
+ * Operator-side: write the canonical branch-protection override marker for
47
+ * `sessionId`. Atomic (delegates to `writeApprovalMarker`). Caller is
48
+ * `harness approve branch-protection`, run from the operator's un-hooked
49
+ * shell; if the agent could reach this path the gate's value would
50
+ * collapse, so it lives behind the approve CLI.
51
+ */
52
+ export declare function writeBranchProtectionMarker(generatedDir: string, sessionId: string, marker: ApprovalMarker): string;
53
+ /**
54
+ * Gate-side: is the operator's branch-protection override marker present
55
+ * for `sessionId`? Inherits `checkApprovalMarker`'s contract
56
+ * (existence-is-enough, symlink rejection, optional freshness via
57
+ * `maxAgeMs`); only the namespaced filename differs.
58
+ */
59
+ export declare function checkBranchProtectionMarker(generatedDir: string, sessionId: string, opts?: CheckApprovalMarkerOptions): MarkerCheck;
19
60
  /**
20
61
  * Freshness window for the producer tag. Five minutes lets a single
21
62
  * branch-check satisfy a whole edit batch without re-running for every
@@ -6,6 +6,7 @@
6
6
  // hook branch-protection` (blocker) — both under `src/cli/`. This module
7
7
  // is the small shared surface they pull from: tag formats, default
8
8
  // protected list, config parsing.
9
+ import { checkApprovalMarker, writeApprovalMarker, } from "./understanding-before-execution-runtime.js";
9
10
  export const PACK_NAME = "branch-protection";
10
11
  /**
11
12
  * Ledger tag written by the producer when the current branch is NOT in
@@ -15,14 +16,60 @@ export const PACK_NAME = "branch-protection";
15
16
  */
16
17
  export const NON_PROTECTED_TAG_PREFIX = "branch:non-protected";
17
18
  /**
18
- * Operator escape-hatch tag. Set via `mcp__agent-grounding__ledger_add`
19
- * (Bash is gated by this very pack, so a shell-based override would be
20
- * unreachable). The blocker substring-matches this prefix; the trailing
21
- * `:<reason>` is a free-form note the operator types so a later audit
22
- * can read WHY the override fired (e.g. `branch-protection-ack:hotfix
23
- * for prod`).
19
+ * Operator escape-hatch tag, kept as a best-effort AUDIT echo only.
20
+ *
21
+ * SECURITY (audit finding #39): this tag is NO LONGER a trusted override
22
+ * signal. The agent has direct `mcp__agent-grounding__ledger_add` access,
23
+ * so it could self-write `branch-protection-ack:<anything>` and bless its
24
+ * own protected-branch edit — exactly the self-approval backdoor the
25
+ * understanding gate closed in agent-tasks/88ca4bb3 by moving the
26
+ * canonical approval to a filesystem marker. The blocker now consults the
27
+ * operator-only marker file (see `checkBranchProtectionMarker` below); the
28
+ * `harness approve branch-protection` verb still records this ledger tag
29
+ * so `harness audit` / forensics keep a trail, but its presence alone
30
+ * never satisfies the gate. The trailing `:<reason>` stays free-form.
24
31
  */
25
32
  export const ACK_TAG_PREFIX = "branch-protection-ack";
33
+ /**
34
+ * Marker-name namespace for an operator-written branch-protection
35
+ * override. The marker lives in the shared `.approvals/` directory under
36
+ * `harness.generated/` (the same directory the understanding gate uses),
37
+ * prefixed so it can never be confused with an understanding-gate session
38
+ * marker (`.approvals/<sessionId>`) or a task marker (`.approvals/task-<id>`):
39
+ * Claude Code / Codex session ids are UUIDs and never start with this
40
+ * literal, so the three namespaces stay disjoint.
41
+ *
42
+ * Why a marker and not the `branch-protection-ack` ledger tag: only a
43
+ * process the operator launched (their `!`-shell or any un-hooked
44
+ * terminal) can write under `harness.generated/` — Edit / Write / Bash
45
+ * are all gated, and the configured MCP servers expose no filesystem
46
+ * write. So the marker is the canonical override signal; the ledger row
47
+ * is a best-effort audit echo only.
48
+ */
49
+ export const BRANCH_PROTECTION_MARKER_PREFIX = "branch-protection-";
50
+ /** Marker filename (inside `.approvals/`) for a session's branch-protection override. */
51
+ export function branchProtectionMarkerName(sessionId) {
52
+ return `${BRANCH_PROTECTION_MARKER_PREFIX}${sessionId}`;
53
+ }
54
+ /**
55
+ * Operator-side: write the canonical branch-protection override marker for
56
+ * `sessionId`. Atomic (delegates to `writeApprovalMarker`). Caller is
57
+ * `harness approve branch-protection`, run from the operator's un-hooked
58
+ * shell; if the agent could reach this path the gate's value would
59
+ * collapse, so it lives behind the approve CLI.
60
+ */
61
+ export function writeBranchProtectionMarker(generatedDir, sessionId, marker) {
62
+ return writeApprovalMarker(generatedDir, branchProtectionMarkerName(sessionId), marker);
63
+ }
64
+ /**
65
+ * Gate-side: is the operator's branch-protection override marker present
66
+ * for `sessionId`? Inherits `checkApprovalMarker`'s contract
67
+ * (existence-is-enough, symlink rejection, optional freshness via
68
+ * `maxAgeMs`); only the namespaced filename differs.
69
+ */
70
+ export function checkBranchProtectionMarker(generatedDir, sessionId, opts = {}) {
71
+ return checkApprovalMarker(generatedDir, branchProtectionMarkerName(sessionId), opts);
72
+ }
26
73
  /**
27
74
  * Freshness window for the producer tag. Five minutes lets a single
28
75
  * branch-check satisfy a whole edit batch without re-running for every
@@ -1 +1 @@
1
- {"version":3,"file":"branch-protection-runtime.js","sourceRoot":"","sources":["../../../src/policy-packs/builtin/branch-protection-runtime.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,EAAE;AACF,kEAAkE;AAClE,yEAAyE;AACzE,sEAAsE;AACtE,yEAAyE;AACzE,mEAAmE;AACnE,kCAAkC;AAIlC,MAAM,CAAC,MAAM,SAAS,GAAG,mBAAmB,CAAC;AAE7C;;;;;GAKG;AACH,MAAM,CAAC,MAAM,wBAAwB,GAAG,sBAAsB,CAAC;AAE/D;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,uBAAuB,CAAC;AAEtD;;;;;GAKG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC;AAEnD,4EAA4E;AAC5E,MAAM,CAAC,MAAM,0BAA0B,GAAsB;IAC3D,QAAQ;IACR,MAAM;IACN,SAAS;CACV,CAAC;AAEF;;;;;;;;;GASG;AACH,MAAM,UAAU,wBAAwB,CAAC,IAAgB;IAIvD,MAAM,GAAG,GAAG,IAAI,CAAC,MAAM,CAAC,oBAAoB,CAAC,CAAC;IAC9C,IAAI,GAAG,KAAK,SAAS,EAAE,CAAC;QACtB,OAAO,EAAE,QAAQ,EAAE,CAAC,GAAG,0BAA0B,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;IACtE,CAAC;IACD,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;QACxB,OAAO;YACL,QAAQ,EAAE,CAAC,GAAG,0BAA0B,CAAC;YACzC,OAAO,EAAE,gBAAgB,IAAI,CAAC,IAAI,kEAAkE,OAAO,GAAG,+BAA+B,0BAA0B,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI;SACvL,CAAC;IACJ,CAAC;IACD,MAAM,EAAE,GAAa,EAAE,CAAC;IACxB,MAAM,GAAG,GAAc,EAAE,CAAC;IAC1B,KAAK,MAAM,KAAK,IAAI,GAAG,EAAE,CAAC;QACxB,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC;YAAE,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;;YAC7D,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACvB,CAAC;IACD,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACpB,OAAO;YACL,QAAQ,EAAE,CAAC,GAAG,0BAA0B,CAAC;YACzC,OAAO,EAAE,gBAAgB,IAAI,CAAC,IAAI,6GAA6G,0BAA0B,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI;SACzL,CAAC;IACJ,CAAC;IACD,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACnB,OAAO;YACL,QAAQ,EAAE,EAAE;YACZ,OAAO,EAAE,gBAAgB,IAAI,CAAC,IAAI,wCAAwC,GAAG,CAAC,MAAM,mBAAmB,GAAG,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,WAAW,EAAE,CAAC,MAAM,aAAa,EAAE,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,KAAK,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI;SACvN,CAAC;IACJ,CAAC;IACD,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;AACzC,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,iBAAiB,CAAC,MAAc,EAAE,aAAgC;IAChF,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IACrC,OAAO,aAAa,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;AACxC,CAAC"}
1
+ {"version":3,"file":"branch-protection-runtime.js","sourceRoot":"","sources":["../../../src/policy-packs/builtin/branch-protection-runtime.ts"],"names":[],"mappings":"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"}
@@ -16,18 +16,23 @@
16
16
  // consults the ledger on every Write/Edit (or `apply_patch`) and
17
17
  // emits a Claude Code deny envelope unless either:
18
18
  // - a fresh (<5m) `branch:non-protected` tag exists, OR
19
- // - a `branch-protection-ack:` override tag exists (any age,
20
- // written by the operator via `mcp__agent-grounding__ledger_add`
21
- // since Bash is gated by this same pack).
19
+ // - the operator-only override marker exists at
20
+ // `harness.generated/.approvals/branch-protection-<sessionId>`,
21
+ // written by `harness approve branch-protection`. The legacy
22
+ // `branch-protection-ack:` ledger tag is no longer trusted as an
23
+ // override (audit finding #39): it is agent-writable via
24
+ // `mcp__agent-grounding__ledger_add`, so it could self-bless an
25
+ // edit. The marker lives under `harness.generated/`, which Edit /
26
+ // Write / Bash are all gated from writing.
22
27
  //
23
28
  // The producer is also runnable on-demand from the operator's `!` shell
24
29
  // — same CLI verb, no SessionStart event piped on stdin — so an agent
25
30
  // that just branched can refresh the gate without restarting the
26
31
  // session.
27
32
  //
28
- // Pack is OFF by default: it must be enabled per-installation via
29
- // `harness pack add branch-protection`. The `full` init template does
30
- // NOT wire it (revisit after one cycle of operator feedback).
33
+ // Enabled per-installation via `harness pack add branch-protection`.
34
+ // The `full` init template wires it with `enabled: true` (see
35
+ // src/cli/init/templates.ts); the `solo` / `team` templates do not.
31
36
  import { z } from "zod";
32
37
  import { PolicyUxSchema } from "../../schema/policies.js";
33
38
  import { DEFAULT_RUNTIME } from "../runtime.js";
@@ -72,7 +77,7 @@ function buildHooks(runtime) {
72
77
  command: BLOCKER_COMMAND,
73
78
  blocking: "hard",
74
79
  budget_ms: 5000,
75
- description: `Blocker: deny ${blockerMatch} on protected branches unless a fresh branch:non-protected tag or a branch-protection-ack override exists in the ledger.`,
80
+ description: `Blocker: deny ${blockerMatch} on protected branches unless a fresh branch:non-protected tag exists in the ledger or the operator-only override marker (harness approve branch-protection) is present.`,
76
81
  },
77
82
  ];
78
83
  }
@@ -113,7 +118,8 @@ While this pack is enabled, hooks are wired into the ${settingsArtefact}:
113
118
  \`${blockerMatch}\`: refuses the tool call unless EITHER
114
119
  - a \`${NON_PROTECTED_TAG_PREFIX}\` tag exists in the ledger from
115
120
  within the last ${minutes} minutes, OR
116
- - a \`${ACK_TAG_PREFIX}:<reason>\` override tag exists (any age).
121
+ - the operator-only override marker exists at
122
+ \`harness.generated/.approvals/branch-protection-<sessionId>\`.
117
123
 
118
124
  ## Escape hatches
119
125
 
@@ -122,12 +128,16 @@ While this pack is enabled, hooks are wired into the ${settingsArtefact}:
122
128
  is gated by the Understanding Gate but the producer command is itself
123
129
  a \`harness ...\` invocation that the gate's allowlist accepts.
124
130
 
125
- - **Explicit override** (any age, lasts the session): write the ack tag
126
- via \`mcp__agent-grounding__ledger_add\` with
127
- \`content: "${ACK_TAG_PREFIX}:<reason>"\`. Use this when you have a
128
- deliberate reason to edit a protected branch version bumps, CI
129
- workflow patches, etc. The override survives session restarts only as
130
- long as the ledger row does.
131
+ - **Explicit override** (operator only): from an un-hooked shell run
132
+ \`harness approve branch-protection --session <sessionId>\`. This writes
133
+ the canonical approval marker the blocker consults. Use it when you have
134
+ a deliberate reason to edit a protected branch (version bumps, CI
135
+ workflow patches, hotfixes). SECURITY (audit finding #39): a
136
+ \`${ACK_TAG_PREFIX}:<reason>\` ledger tag is NO LONGER sufficient on its
137
+ own — it is agent-writable via \`mcp__agent-grounding__ledger_add\`, so
138
+ the gate would otherwise be self-approvable. The approve verb still
139
+ records that ledger tag for audit, but only the marker file (which the
140
+ agent cannot write) opens the gate.
131
141
 
132
142
  ## Out of scope (v1)
133
143
 
@@ -1 +1 @@
1
- {"version":3,"file":"branch-protection.js","sourceRoot":"","sources":["../../../src/policy-packs/builtin/branch-protection.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"branch-protection.js","sourceRoot":"","sources":["../../../src/policy-packs/builtin/branch-protection.ts"],"names":[],"mappings":"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"}
@@ -36,6 +36,15 @@ export interface Verdict {
36
36
  }
37
37
  /** Env knob that overrides the verdict directory (mirrors the producer). */
38
38
  export declare const VERDICT_DIR_ENV = "SOLUTION_VERDICT_DIR";
39
+ /**
40
+ * Env knob that supplies the verdict id for SOLO / non-agent-tasks sessions.
41
+ * The completion-gate consults it ONLY when no agent-tasks `active-claim` is
42
+ * recorded (resolution order: active-claim first, then this env, then
43
+ * fail-closed), so a claimed session's id stays authoritative and cannot be
44
+ * redirected by an env var. A sessionId fallback is intentionally still NOT a
45
+ * source (the wrong-scope bug class understanding-gate closed).
46
+ */
47
+ export declare const VERDICT_ID_ENV = "SOLUTION_VERDICT_ID";
39
48
  /**
40
49
  * Stable tail of the default verdict dir. The write-guard's reference
41
50
  * detection matches on this so ANY spelling of the home prefix is caught
@@ -61,6 +70,15 @@ export declare function verdictDir(env?: NodeJS.ProcessEnv, homedir?: () => stri
61
70
  */
62
71
  export declare function sanitizeVerdictId(id: string): string;
63
72
  export declare function verdictPathFor(dir: string, id: string): string;
73
+ /**
74
+ * Resolve the explicit verdict id from `SOLUTION_VERDICT_ID`, or null when it
75
+ * is unset, blank, or not a safe single path segment. Validated through
76
+ * `sanitizeVerdictId` so a traversal-y or empty value fails closed here
77
+ * (returns null -> the gate denies) rather than reaching the marker read. This
78
+ * is the solo / non-agent-tasks fallback the completion-gate uses only when no
79
+ * active-claim is present.
80
+ */
81
+ export declare function resolveExplicitVerdictId(env?: NodeJS.ProcessEnv): string | null;
64
82
  /**
65
83
  * Read + validate the verdict marker for `id`, or null when it is absent,
66
84
  * unparseable, a symlink, or not a regular file. The lstat + symlink reject
@@ -75,6 +75,15 @@ export function resolveProtectedCompletionTools(pack) {
75
75
  }
76
76
  /** Env knob that overrides the verdict directory (mirrors the producer). */
77
77
  export const VERDICT_DIR_ENV = "SOLUTION_VERDICT_DIR";
78
+ /**
79
+ * Env knob that supplies the verdict id for SOLO / non-agent-tasks sessions.
80
+ * The completion-gate consults it ONLY when no agent-tasks `active-claim` is
81
+ * recorded (resolution order: active-claim first, then this env, then
82
+ * fail-closed), so a claimed session's id stays authoritative and cannot be
83
+ * redirected by an env var. A sessionId fallback is intentionally still NOT a
84
+ * source (the wrong-scope bug class understanding-gate closed).
85
+ */
86
+ export const VERDICT_ID_ENV = "SOLUTION_VERDICT_ID";
78
87
  /**
79
88
  * Stable tail of the default verdict dir. The write-guard's reference
80
89
  * detection matches on this so ANY spelling of the home prefix is caught
@@ -116,6 +125,29 @@ export function sanitizeVerdictId(id) {
116
125
  export function verdictPathFor(dir, id) {
117
126
  return path.join(dir, `${sanitizeVerdictId(id)}.json`);
118
127
  }
128
+ /**
129
+ * Resolve the explicit verdict id from `SOLUTION_VERDICT_ID`, or null when it
130
+ * is unset, blank, or not a safe single path segment. Validated through
131
+ * `sanitizeVerdictId` so a traversal-y or empty value fails closed here
132
+ * (returns null -> the gate denies) rather than reaching the marker read. This
133
+ * is the solo / non-agent-tasks fallback the completion-gate uses only when no
134
+ * active-claim is present.
135
+ */
136
+ export function resolveExplicitVerdictId(env = process.env) {
137
+ const raw = env[VERDICT_ID_ENV];
138
+ if (typeof raw !== "string")
139
+ return null;
140
+ const trimmed = raw.trim();
141
+ if (trimmed.length === 0)
142
+ return null;
143
+ try {
144
+ sanitizeVerdictId(trimmed);
145
+ }
146
+ catch {
147
+ return null;
148
+ }
149
+ return trimmed;
150
+ }
119
151
  /**
120
152
  * Read + validate the verdict marker for `id`, or null when it is absent,
121
153
  * unparseable, a symlink, or not a regular file. The lstat + symlink reject
@@ -1 +1 @@
1
- {"version":3,"file":"solution-acceptance-runtime.js","sourceRoot":"","sources":["../../../src/policy-packs/builtin/solution-acceptance-runtime.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"solution-acceptance-runtime.js","sourceRoot":"","sources":["../../../src/policy-packs/builtin/solution-acceptance-runtime.ts"],"names":[],"mappings":"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"}
@@ -12,6 +12,18 @@ export interface PersistedReport {
12
12
  sessionId: string | null;
13
13
  approvalStatus: string | null;
14
14
  approvedAt: string | null;
15
+ /**
16
+ * ISO timestamp the producer stamped when it wrote the report; null
17
+ * for legacy reports without the field.
18
+ */
19
+ createdAt: string | null;
20
+ /**
21
+ * Effective creation time in epoch ms, resolved `createdAt` →
22
+ * filename ISO prefix → file mtime. Unlike mtime alone this survives
23
+ * the approval rewrite (which bumps mtime and would otherwise make a
24
+ * weeks-old report sort as the freshest, harness-discovery C1).
25
+ */
26
+ createdAtMs: number;
15
27
  }
16
28
  /**
17
29
  * Env var the persisted-report directory can be set from. Honored by
@@ -44,14 +56,39 @@ export declare function reportsDirForManifest(manifestPath: string): string;
44
56
  /** Build the per-session ledger tag the pack searches for. */
45
57
  export declare function approvedLedgerTagFor(sessionId: string): string;
46
58
  /**
47
- * List persisted reports under `dir`, newest-first by mtime. Missing
48
- * directory returns []. Any I/O error on a single file is silently
49
- * skipped; the caller falls through to the ledger result. The package
50
- * writes filenames as `<iso>-<slug>-<hash>.json` so the alphabetical
51
- * sort would also work for ISO prefixes, but mtime is robust against
52
- * the package changing its naming convention later.
59
+ * List persisted reports under `dir`, newest-first by creation time
60
+ * (JSON `createdAt`, falling back to the filename ISO prefix, falling
61
+ * back to mtime). Missing directory returns []. Any I/O error on a
62
+ * single file is silently skipped; the caller falls through to the
63
+ * ledger result.
64
+ *
65
+ * Creation time, NOT mtime, is the sort key: `harness approve
66
+ * understanding` rewrites the report it flips, which bumps mtime and
67
+ * made an old just-approved report sort as the freshest
68
+ * (harness-discovery C1). mtime survives only as the last-resort
69
+ * fallback for files that carry neither timestamp.
53
70
  */
54
71
  export declare function listPersistedReports(dir: string): PersistedReport[];
72
+ /**
73
+ * Maximum age a sessionId-null report may have for the tolerant
74
+ * fallback to adopt it on the `harness approve understanding` path.
75
+ * Sized for the real flow (Stop hook persists at turn end, operator
76
+ * approves within minutes) with slack for a slow read-through. Live
77
+ * repro that motivated it: a 17-day-old pending report got adopted,
78
+ * validated, and stamped for a fresh session because the producer had
79
+ * silently failed to persist the fresh report (harness-discovery C1,
80
+ * friction-log #67).
81
+ */
82
+ export declare const TOLERANT_FALLBACK_MAX_AGE_MS: number;
83
+ /**
84
+ * Tolerance for a sessionId-less candidate whose `createdAt` lies in
85
+ * the FUTURE relative to the approve-time clock. A future creation
86
+ * time is suspect either way: a forged `createdAt` (the producer's
87
+ * Metadata block lets the agent author it) or serious clock skew.
88
+ * Beyond this skew the fallback rejects the candidate just like a
89
+ * stale one rather than trusting a timestamp that cannot be right.
90
+ */
91
+ export declare const TOLERANT_FALLBACK_FUTURE_SKEW_MS: number;
55
92
  export interface FindReportOptions {
56
93
  /**
57
94
  * Behaviour of the sessionId-null tolerant fallback (older Stop-hook
@@ -70,15 +107,50 @@ export interface FindReportOptions {
70
107
  * report into the live session (harness/0dce3880 friction #1).
71
108
  */
72
109
  tolerantFallback?: "any" | "uncompleted";
110
+ /**
111
+ * Maximum age (relative to `now`) of a sessionId-null candidate the
112
+ * tolerant fallback may adopt; older candidates are skipped and
113
+ * surfaced via `FindReportSelection.staleRejected`. Strict sessionId
114
+ * matches are never age-limited. Unset means no limit (the legacy
115
+ * gate-read / expiry contract).
116
+ */
117
+ maxFallbackAgeMs?: number;
118
+ /** Clock anchor for the age computation; defaults to the wall clock. */
119
+ now?: Date;
120
+ }
121
+ export interface FindReportSelection {
122
+ report: PersistedReport | null;
123
+ /**
124
+ * True when `report` was adopted via the sessionId-null tolerant
125
+ * fallback rather than a strict sessionId match. Callers that bind
126
+ * the report to a session (the approve flow) surface this loudly so
127
+ * the operator can verify the adoption.
128
+ */
129
+ fallbackAdopted: boolean;
130
+ /**
131
+ * sessionId-null candidates skipped for exceeding `maxFallbackAgeMs`,
132
+ * newest first. Lets the caller distinguish "no report at all" from
133
+ * "only stale candidates existed", which are different failures: the
134
+ * latter usually means the producer failed to persist the fresh
135
+ * report (harness-discovery C1).
136
+ */
137
+ staleRejected: PersistedReport[];
73
138
  }
74
139
  /**
75
- * Return the freshest report for a given session_id, or the freshest
140
+ * Select the freshest report for a given session_id, or the freshest
76
141
  * applicable report when the persisted file lacks a sessionId field
77
- * (older package versions). null when nothing matches.
142
+ * (older package versions). `report: null` when nothing matches.
78
143
  *
79
144
  * The strict (sessionId-equals) match always wins. The tolerant
80
- * fallback's appetite is controlled by `opts.tolerantFallback` — see
81
- * `FindReportOptions`.
145
+ * fallback's appetite is controlled by `opts.tolerantFallback` and
146
+ * `opts.maxFallbackAgeMs` — see `FindReportOptions`. The selection
147
+ * result carries enough context (`fallbackAdopted`, `staleRejected`)
148
+ * for the caller to be loud about non-strict adoptions.
149
+ */
150
+ export declare function selectReportForSession(reports: PersistedReport[], sessionId: string, opts?: FindReportOptions): FindReportSelection;
151
+ /**
152
+ * Back-compat wrapper around `selectReportForSession` for callers that
153
+ * only need the report (the gate read and expiry paths).
82
154
  */
83
155
  export declare function findLatestReportForSession(reports: PersistedReport[], sessionId: string, opts?: FindReportOptions): PersistedReport | null;
84
156
  export interface PersistedReportApprovalCheck {
@@ -85,7 +85,20 @@ function safeJsonParse(text) {
85
85
  return null;
86
86
  }
87
87
  }
88
- function readPersistedReport(filePath) {
88
+ /**
89
+ * Parse the ISO prefix of a producer filename
90
+ * (`2026-05-24T06-16-39-409Z-<slug>-<hash>.json`) into epoch ms. The
91
+ * producer flattens `:` and `.` to `-` for filesystem safety; undo that
92
+ * before `Date.parse`. null when the name does not carry the prefix.
93
+ */
94
+ function parseFilenameIsoMs(name) {
95
+ const m = /^(\d{4}-\d{2}-\d{2})T(\d{2})-(\d{2})-(\d{2})-(\d{3})Z/.exec(name);
96
+ if (!m)
97
+ return null;
98
+ const ms = Date.parse(`${m[1]}T${m[2]}:${m[3]}:${m[4]}.${m[5]}Z`);
99
+ return Number.isNaN(ms) ? null : ms;
100
+ }
101
+ function readPersistedReport(filePath, mtimeMs) {
89
102
  let raw;
90
103
  try {
91
104
  raw = fs.readFileSync(filePath, "utf8");
@@ -97,20 +110,32 @@ function readPersistedReport(filePath) {
97
110
  if (!parsed || typeof parsed !== "object" || Array.isArray(parsed))
98
111
  return null;
99
112
  const obj = parsed;
113
+ const createdAt = typeof obj["createdAt"] === "string" ? obj["createdAt"] : null;
114
+ const createdAtJsonMs = createdAt !== null ? Date.parse(createdAt) : Number.NaN;
115
+ const createdAtMs = !Number.isNaN(createdAtJsonMs)
116
+ ? createdAtJsonMs
117
+ : (parseFilenameIsoMs(path.basename(filePath)) ?? mtimeMs);
100
118
  return {
101
119
  filePath,
102
120
  sessionId: typeof obj["sessionId"] === "string" ? obj["sessionId"] : null,
103
121
  approvalStatus: typeof obj["approvalStatus"] === "string" ? obj["approvalStatus"] : null,
104
122
  approvedAt: typeof obj["approvedAt"] === "string" ? obj["approvedAt"] : null,
123
+ createdAt,
124
+ createdAtMs,
105
125
  };
106
126
  }
107
127
  /**
108
- * List persisted reports under `dir`, newest-first by mtime. Missing
109
- * directory returns []. Any I/O error on a single file is silently
110
- * skipped; the caller falls through to the ledger result. The package
111
- * writes filenames as `<iso>-<slug>-<hash>.json` so the alphabetical
112
- * sort would also work for ISO prefixes, but mtime is robust against
113
- * the package changing its naming convention later.
128
+ * List persisted reports under `dir`, newest-first by creation time
129
+ * (JSON `createdAt`, falling back to the filename ISO prefix, falling
130
+ * back to mtime). Missing directory returns []. Any I/O error on a
131
+ * single file is silently skipped; the caller falls through to the
132
+ * ledger result.
133
+ *
134
+ * Creation time, NOT mtime, is the sort key: `harness approve
135
+ * understanding` rewrites the report it flips, which bumps mtime and
136
+ * made an old just-approved report sort as the freshest
137
+ * (harness-discovery C1). mtime survives only as the last-resort
138
+ * fallback for files that carry neither timestamp.
114
139
  */
115
140
  export function listPersistedReports(dir) {
116
141
  let names;
@@ -134,34 +159,61 @@ export function listPersistedReports(dir) {
134
159
  }
135
160
  if (!stat.isFile())
136
161
  continue;
137
- const report = readPersistedReport(full);
162
+ const report = readPersistedReport(full, stat.mtimeMs);
138
163
  if (!report)
139
164
  continue;
140
- reports.push({ report, mtimeMs: stat.mtimeMs });
165
+ reports.push(report);
141
166
  }
142
- reports.sort((a, b) => b.mtimeMs - a.mtimeMs);
143
- return reports.map((r) => r.report);
167
+ reports.sort((a, b) => b.createdAtMs - a.createdAtMs);
168
+ return reports;
144
169
  }
145
170
  /**
146
- * Return the freshest report for a given session_id, or the freshest
171
+ * Maximum age a sessionId-null report may have for the tolerant
172
+ * fallback to adopt it on the `harness approve understanding` path.
173
+ * Sized for the real flow (Stop hook persists at turn end, operator
174
+ * approves within minutes) with slack for a slow read-through. Live
175
+ * repro that motivated it: a 17-day-old pending report got adopted,
176
+ * validated, and stamped for a fresh session because the producer had
177
+ * silently failed to persist the fresh report (harness-discovery C1,
178
+ * friction-log #67).
179
+ */
180
+ export const TOLERANT_FALLBACK_MAX_AGE_MS = 15 * 60_000;
181
+ /**
182
+ * Tolerance for a sessionId-less candidate whose `createdAt` lies in
183
+ * the FUTURE relative to the approve-time clock. A future creation
184
+ * time is suspect either way: a forged `createdAt` (the producer's
185
+ * Metadata block lets the agent author it) or serious clock skew.
186
+ * Beyond this skew the fallback rejects the candidate just like a
187
+ * stale one rather than trusting a timestamp that cannot be right.
188
+ */
189
+ export const TOLERANT_FALLBACK_FUTURE_SKEW_MS = 5 * 60_000;
190
+ /**
191
+ * Select the freshest report for a given session_id, or the freshest
147
192
  * applicable report when the persisted file lacks a sessionId field
148
- * (older package versions). null when nothing matches.
193
+ * (older package versions). `report: null` when nothing matches.
149
194
  *
150
195
  * The strict (sessionId-equals) match always wins. The tolerant
151
- * fallback's appetite is controlled by `opts.tolerantFallback` — see
152
- * `FindReportOptions`.
196
+ * fallback's appetite is controlled by `opts.tolerantFallback` and
197
+ * `opts.maxFallbackAgeMs` — see `FindReportOptions`. The selection
198
+ * result carries enough context (`fallbackAdopted`, `staleRejected`)
199
+ * for the caller to be loud about non-strict adoptions.
153
200
  */
154
- export function findLatestReportForSession(reports, sessionId, opts = {}) {
201
+ export function selectReportForSession(reports, sessionId, opts = {}) {
155
202
  // Strict match first.
156
203
  for (const r of reports) {
157
- if (r.sessionId === sessionId)
158
- return r;
204
+ if (r.sessionId === sessionId) {
205
+ return { report: r, fallbackAdopted: false, staleRejected: [] };
206
+ }
159
207
  }
160
208
  // Tolerant fallback: a report without sessionId is treated as
161
209
  // applicable to whichever session is asking. Only kicks in when no
162
- // sessionId-tagged report exists, so harnessed sessions with proper
163
- // tagging never hit this path.
210
+ // matching sessionId-tagged report exists which includes the case
211
+ // where the producer Stop hook silently failed to persist the live
212
+ // session's report, so the candidates here may be entirely unrelated
213
+ // leftovers. `maxFallbackAgeMs` is the guard against adopting those.
164
214
  const mode = opts.tolerantFallback ?? "any";
215
+ const nowMs = (opts.now ?? new Date()).getTime();
216
+ const staleRejected = [];
165
217
  for (const r of reports) {
166
218
  if (r.sessionId !== null)
167
219
  continue;
@@ -172,9 +224,23 @@ export function findLatestReportForSession(reports, sessionId, opts = {}) {
172
224
  // the live session to a stale, unrelated report.
173
225
  continue;
174
226
  }
175
- return r;
227
+ if (opts.maxFallbackAgeMs !== undefined) {
228
+ const ageMs = nowMs - r.createdAtMs;
229
+ if (ageMs > opts.maxFallbackAgeMs || ageMs < -TOLERANT_FALLBACK_FUTURE_SKEW_MS) {
230
+ staleRejected.push(r);
231
+ continue;
232
+ }
233
+ }
234
+ return { report: r, fallbackAdopted: true, staleRejected };
176
235
  }
177
- return null;
236
+ return { report: null, fallbackAdopted: false, staleRejected };
237
+ }
238
+ /**
239
+ * Back-compat wrapper around `selectReportForSession` for callers that
240
+ * only need the report (the gate read and expiry paths).
241
+ */
242
+ export function findLatestReportForSession(reports, sessionId, opts = {}) {
243
+ return selectReportForSession(reports, sessionId, opts).report;
178
244
  }
179
245
  /**
180
246
  * Phase 6 #6 — substring-pollution defence shared by every PreToolUse