brainclaw 1.19.0 → 1.19.1

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.
Binary file
@@ -1,7 +1,7 @@
1
1
  import { buildOperationalIdentity } from '../core/identity.js';
2
2
  import { memoryExists } from '../core/io.js';
3
3
  import { mutate } from '../core/mutation-pipeline.js';
4
- import { saveClaim, generateClaimId, listClaims } from '../core/claims.js';
4
+ import { saveClaim, generateClaimId, listClaims, claimBaselineFields } from '../core/claims.js';
5
5
  import { rebuildProjectMd } from '../core/markdown.js';
6
6
  import { loadState, saveState } from '../core/state.js';
7
7
  import { nowISO } from '../core/ids.js';
@@ -64,6 +64,10 @@ export function runClaim(description, options) {
64
64
  status: 'active',
65
65
  expires_at: options.ttl ? parseTtl(options.ttl) : undefined,
66
66
  model: resolveCurrentModel(options.cwd),
67
+ // pln#636 C0-b / trp#1292 — resolved here, OUTSIDE the mutate() below, so the
68
+ // git subprocess never widens the critical section that serializes writes on
69
+ // the claims store.
70
+ ...claimBaselineFields(options.cwd),
67
71
  };
68
72
  try {
69
73
  mutate({ cwd: options.cwd }, () => {
@@ -18,7 +18,7 @@ import { getTriggeredItems, renderTriggeredItems } from '../core/lifecycle.js';
18
18
  import { buildContext } from '../core/context.js';
19
19
  import { checkBrainclawInstallableUpdate, getInstalledBrainclawVersion, renderBrainclawInstallableUpdateNotice } from '../core/brainclaw-version.js';
20
20
  import { loadConfig } from '../core/config.js';
21
- import { generateClaimId, loadClaim, saveClaim, adoptClaimSession, releaseClaimWithCascade } from '../core/claims.js';
21
+ import { generateClaimId, loadClaim, saveClaim, adoptClaimSession, releaseClaimWithCascade, claimBaselineFields } from '../core/claims.js';
22
22
  import { releaseClaimNextActions } from '../core/next-actions.js';
23
23
  import { reconcileClaimConformity } from '../core/claim-conformity.js';
24
24
  import { pushStructuredWarning } from '../core/warnings.js';
@@ -128,6 +128,11 @@ export async function handleBclawClaim(payload, ctx) {
128
128
  worktree_path: worktreePath,
129
129
  expires_at: claimExpiresAt,
130
130
  handoff_mode: handoffMode,
131
+ // pln#636 C0-b / trp#1292 — this handler builds its claim literal instead of
132
+ // going through acquireClaimScope, which is why the baseline was missing on
133
+ // every MCP-created claim and the conformity reconcile never had anything to
134
+ // compare against.
135
+ ...claimBaselineFields(claimCwd),
131
136
  }, claimCwd);
132
137
  appendAuditEntry({ actor: resolvedIdentity.agent_name, actor_id: resolvedIdentity.agent_id, action: 'claim', item_id: claimId, item_type: 'claim', scope: claimScope, session_id: identity.session_id, host_id: identity.host_id }, claimCwd);
133
138
  // Post-claim policy check: surface constraints/traps as warnings
@@ -13,7 +13,7 @@ import { collectLoadValidationWarnings, findLoadValidationWarning, loadState } f
13
13
  import { memoryExists, MEMORY_DIR } from '../core/io.js';
14
14
  import { getEntity, listEntities, boundListResult, DEFAULT_FIND_CHAR_BUDGET, GRAMMAR_FILTER_CONTRACT, } from '../core/entity-operations.js';
15
15
  import { handoffDiffPreviewNote } from '../core/handoff-snapshot.js';
16
- import { generateClaimId, listClaims, loadClaim, saveClaim, adoptClaimSession } from '../core/claims.js';
16
+ import { generateClaimId, listClaims, loadClaim, saveClaim, adoptClaimSession, claimBaselineFields } from '../core/claims.js';
17
17
  import { assertCrossProjectBoundary, checkPolicy } from '../core/policy.js';
18
18
  import { startSession } from './session-start.js';
19
19
  import { AgentIdentityResolutionError, AgentTrustError, resolveCurrentModel, } from '../core/agent-registry.js';
@@ -1302,6 +1302,11 @@ async function _executeMcpToolCallInner(payload) {
1302
1302
  status: 'active',
1303
1303
  plan_id: workReq.planId,
1304
1304
  model: currentModel,
1305
+ // pln#636 C0-b / trp#1292 — bclaw_work(execute) is the entry point the
1306
+ // session protocol tells every agent to start with, so a missing
1307
+ // baseline here made the conformity reconcile inert for nearly all
1308
+ // real claims.
1309
+ ...claimBaselineFields(targetCwd),
1305
1310
  }, targetCwd);
1306
1311
  appendAuditEntry({ actor: sessionResult.agent, actor_id: sessionResult.agent_id, action: 'claim', item_id: claimId, item_type: 'claim', scope: workReq.scope, session_id: sessionResult.session_id }, targetCwd);
1307
1312
  claimStatus = 'created';
@@ -150,6 +150,34 @@ export function resolveClaimBaseSha(cwd) {
150
150
  return undefined;
151
151
  }
152
152
  }
153
+ /**
154
+ * The baseline fields every NEW claim must carry, ready to spread into a claim
155
+ * literal: `{ ...claimBaselineFields(cwd) }`.
156
+ *
157
+ * WHY A HELPER AND NOT AN INLINE CALL. `base_sha` shipped in 1.19.0 stamped from
158
+ * exactly ONE place — inside `acquireClaimScope` — and it turned out nothing
159
+ * user-facing calls that function. All four real creation paths
160
+ * (`bclaw_work(execute)`, `bclaw_claim`, the CLI `claim create`, and
161
+ * `createCoordinatorClaim`) build their claim literal inline and call `saveClaim`
162
+ * directly, so NO real claim ever got a baseline and the whole conformity
163
+ * reconcile that depends on it was inert (trp#1292). A named, greppable helper is
164
+ * what makes "did this creation path stamp the baseline?" answerable, and it is
165
+ * asserted per surface rather than only on the core function — testing
166
+ * `acquireClaimScope` directly is exactly what hid the gap.
167
+ *
168
+ * Returns an EMPTY object rather than `{ base_sha: undefined }` so a claim created
169
+ * outside a git repo has no such key at all, matching the "optional, never
170
+ * backfilled" contract the schema documents.
171
+ *
172
+ * Deliberately NOT applied inside `saveClaim`: that function also persists
173
+ * UPDATES (release, patch, adoption), and the baseline must be a fixed point —
174
+ * re-stamping it on every save is precisely the moving-ground failure that made
175
+ * `git diff HEAD` unusable in the first place.
176
+ */
177
+ export function claimBaselineFields(cwd) {
178
+ const base_sha = resolveClaimBaseSha(cwd);
179
+ return base_sha ? { base_sha } : {};
180
+ }
153
181
  /**
154
182
  * Atomically check for an active claim on `scope` and save a new one if absent.
155
183
  *
@@ -160,7 +188,7 @@ export function acquireClaimScope(input, cwd) {
160
188
  // Resolved OUTSIDE the mutate callback: one git call per acquisition, and it
161
189
  // stays off the critical section (mutate serializes filesystem writes on the
162
190
  // claims store, so a subprocess spawn inside it would widen the lock window).
163
- const baseSha = resolveClaimBaseSha(cwd);
191
+ const baseline = claimBaselineFields(cwd);
164
192
  return mutate({ cwd }, () => {
165
193
  const conflictingClaim = listClaims(cwd).find((claim) => claim.status === 'active' && claim.scope === input.scope);
166
194
  if (conflictingClaim) {
@@ -180,7 +208,7 @@ export function acquireClaimScope(input, cwd) {
180
208
  model: input.model,
181
209
  // pln#636 C0-b — capture the baseline while we know it. Absent when the
182
210
  // project is not a git repo; downstream treats that as unverifiable.
183
- ...(baseSha ? { base_sha: baseSha } : {}),
211
+ ...baseline,
184
212
  ...(input.paths?.length ? { paths: input.paths } : {}),
185
213
  };
186
214
  saveClaimUnlocked(claim, cwd);
@@ -854,6 +882,10 @@ export function createCoordinatorClaim(options) {
854
882
  };
855
883
  }
856
884
  const claimId = generateClaimId();
885
+ // Resolved OUTSIDE the lock below, for the same reason acquireClaimScope does
886
+ // it: a subprocess spawn inside the mutate callback would widen the critical
887
+ // section that serializes writes on the claims store.
888
+ const baseline = claimBaselineFields(options.cwd);
857
889
  let worktreePath;
858
890
  let worktreeWarning;
859
891
  // Create isolated worktree (matching bclaw_claim MCP handler behavior).
@@ -905,6 +937,7 @@ export function createCoordinatorClaim(options) {
905
937
  created_at: nowISO(),
906
938
  status: 'active',
907
939
  worktree_path: worktreePath,
940
+ ...baseline, // pln#636 C0-b / trp#1292 — dispatched lanes need it most
908
941
  }, options.cwd);
909
942
  return { claimId, worktreePath, worktreeWarning, reusedExisting: false };
910
943
  });
package/dist/facts.js CHANGED
@@ -1,8 +1,8 @@
1
1
  // Generated by scripts/emit-site-facts.mjs at build time. Do not edit manually.
2
- // Source: brainclaw v1.19.0 on 2026-08-01T21:36:53.526Z
2
+ // Source: brainclaw v1.19.1 on 2026-08-02T07:16:39.143Z
3
3
  export const FACTS = {
4
- "version": "1.19.0",
5
- "generated_at": "2026-08-01T21:36:53.526Z",
4
+ "version": "1.19.1",
5
+ "generated_at": "2026-08-02T07:16:39.143Z",
6
6
  "tools": {
7
7
  "count": 67,
8
8
  "published_count": 65,
@@ -474,7 +474,7 @@ export const FACTS = {
474
474
  },
475
475
  "bench": {
476
476
  "schema": "brainclaw.bench.v1",
477
- "generated_at": "2026-08-01T21:36:51.459Z",
477
+ "generated_at": "2026-08-02T07:16:37.042Z",
478
478
  "node_version": "v24.18.0",
479
479
  "platform": "linux-x64",
480
480
  "repeats": 3,
@@ -483,7 +483,7 @@ export const FACTS = {
483
483
  "name": "cold_onboard",
484
484
  "volume": "empty",
485
485
  "description": "fresh machine → init → first useful context. Baseline for time-to-first-value.",
486
- "duration_ms_median": 74,
486
+ "duration_ms_median": 81,
487
487
  "payload_chars_median": 1640,
488
488
  "payload_tokens_est_median": 410
489
489
  },
@@ -491,7 +491,7 @@ export const FACTS = {
491
491
  "name": "warm_work",
492
492
  "volume": "medium",
493
493
  "description": "bclaw_work consult over a real-shaped store (~200 plans / 500 handoffs / 450 claims).",
494
- "duration_ms_median": 124,
494
+ "duration_ms_median": 123,
495
495
  "payload_chars_median": 2626,
496
496
  "payload_tokens_est_median": 657
497
497
  },
@@ -499,7 +499,7 @@ export const FACTS = {
499
499
  "name": "first_edit",
500
500
  "volume": "medium",
501
501
  "description": "code_find + code_brief on the fresh-agent path (missing index, first touch).",
502
- "duration_ms_median": 14,
502
+ "duration_ms_median": 12,
503
503
  "payload_chars_median": 499,
504
504
  "payload_tokens_est_median": 125
505
505
  }
package/dist/facts.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
- "version": "1.19.0",
3
- "generated_at": "2026-08-01T21:36:53.526Z",
2
+ "version": "1.19.1",
3
+ "generated_at": "2026-08-02T07:16:39.143Z",
4
4
  "tools": {
5
5
  "count": 67,
6
6
  "published_count": 65,
@@ -472,7 +472,7 @@
472
472
  },
473
473
  "bench": {
474
474
  "schema": "brainclaw.bench.v1",
475
- "generated_at": "2026-08-01T21:36:51.459Z",
475
+ "generated_at": "2026-08-02T07:16:37.042Z",
476
476
  "node_version": "v24.18.0",
477
477
  "platform": "linux-x64",
478
478
  "repeats": 3,
@@ -481,7 +481,7 @@
481
481
  "name": "cold_onboard",
482
482
  "volume": "empty",
483
483
  "description": "fresh machine → init → first useful context. Baseline for time-to-first-value.",
484
- "duration_ms_median": 74,
484
+ "duration_ms_median": 81,
485
485
  "payload_chars_median": 1640,
486
486
  "payload_tokens_est_median": 410
487
487
  },
@@ -489,7 +489,7 @@
489
489
  "name": "warm_work",
490
490
  "volume": "medium",
491
491
  "description": "bclaw_work consult over a real-shaped store (~200 plans / 500 handoffs / 450 claims).",
492
- "duration_ms_median": 124,
492
+ "duration_ms_median": 123,
493
493
  "payload_chars_median": 2626,
494
494
  "payload_tokens_est_median": 657
495
495
  },
@@ -497,7 +497,7 @@
497
497
  "name": "first_edit",
498
498
  "volume": "medium",
499
499
  "description": "code_find + code_brief on the fresh-agent path (missing index, first touch).",
500
- "duration_ms_median": 14,
500
+ "duration_ms_median": 12,
501
501
  "payload_chars_median": 499,
502
502
  "payload_tokens_est_median": 125
503
503
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "brainclaw",
3
- "version": "1.19.0",
3
+ "version": "1.19.1",
4
4
  "description": "Shared project memory for humans and coding agents.",
5
5
  "type": "module",
6
6
  "repository": {