plumbbob 0.11.1 → 0.11.2

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.
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "plumbbob",
3
3
  "displayName": "PlumbBob",
4
- "version": "0.11.1",
4
+ "version": "0.11.2",
5
5
  "description": "Attention-first build process — driver skills + a CLI that keep you the decider: guidance on the work, a latch on the record.",
6
6
  "author": { "name": "Rob McLarty", "email": "hello@robmclarty.com", "url": "https://robmclarty.com" },
7
7
  "homepage": "https://github.com/robmclarty/plumbbob#readme",
@@ -311,7 +311,7 @@ function classifyRecapRow(name, value) {
311
311
  test(/^bent\b/, 'failing') ??
312
312
  test(/^drift\b/, 'drift'));
313
313
  case 'seam':
314
- return test(/^held\b/, 'true') ?? test(/^strayed\b/, 'failing') ?? test(/^drift\b/, 'drift');
314
+ return test(/^held\b/, 'true') ?? test(/^strayed\b/, 'advisory') ?? test(/^drift\b/, 'drift');
315
315
  }
316
316
  }
317
317
  /**
@@ -381,6 +381,13 @@ const NOT_STANDING = { glyph: '✗', state: 'Not standing' };
381
381
  * drift beats a live failure beats an advisory beats plumb, and each rung
382
382
  * names the one component that earned it. The advisory rung runs in a fixed
383
383
  * order, the seam stray first.
384
+ *
385
+ * A strayed seam is an advisory, never a failure: a path outside the seam
386
+ * says either that the work wandered or that the line was drawn too tight,
387
+ * and truing the diff fixes neither. At the pause the measured seam row
388
+ * carries the stray; at the boundary the tree is clean, the row has vanished,
389
+ * and the stat the checkpoint bumped carries it instead. Both name it
390
+ * `seam strayed`, so the rung does not change between the two.
384
391
  */
385
392
  export function foldVerdict(rows, stats) {
386
393
  for (const name of RECAP_ROW_NAMES) {
@@ -394,11 +401,17 @@ export function foldVerdict(rows, stats) {
394
401
  return { ladder: OUT_OF_PLUMB, worst: `${name} ${row.word}` };
395
402
  }
396
403
  }
404
+ for (const name of RECAP_ROW_NAMES) {
405
+ const row = rows[name];
406
+ if (row !== undefined && row.verdict === 'advisory') {
407
+ return { ladder: A_HAIR_OFF, worst: `${name} ${row.word}` };
408
+ }
409
+ }
397
410
  if (stats.driftWarnings > 0) {
398
411
  // First of the advisory rung, and uncounted: the stat bumps once per
399
412
  // checkpoint rather than once per stray path, and this is the one advisory
400
413
  // that asks a question of the plan rather than of the work.
401
- return { ladder: A_HAIR_OFF, worst: 'staged outside the seam' };
414
+ return { ladder: A_HAIR_OFF, worst: 'seam strayed' };
402
415
  }
403
416
  if (stats.redChecks > 0) {
404
417
  return { ladder: A_HAIR_OFF, worst: `${stats.redChecks} red run${stats.redChecks === 1 ? '' : 's'} before green` };
@@ -469,10 +482,12 @@ export function summaryCheckRow(summary) {
469
482
  * (the row then vanishes, or the model's attested row stands).
470
483
  *
471
484
  * Green sizes the declared seam: how many of its tokens the diff actually
472
- * touched, and that nothing landed outside them. Red states the size of the
473
- * problem and lets the paths themselves be the evidence: one stray is the `→`
474
- * pointer, and several break onto `- ` lines. `paths` are work-plane changes,
475
- * artifacts already filtered by the caller.
485
+ * touched, and that nothing landed outside them. A stray states the size of
486
+ * the problem and lets the paths themselves be the evidence: one stray is the
487
+ * `→` pointer, and several break onto `- ` lines. It is an advisory, not a
488
+ * failure (the seam is awareness, not a lock), so the fold puts it on the
489
+ * third rung, never the second. `paths` are work-plane changes, artifacts
490
+ * already filtered by the caller.
476
491
  */
477
492
  export function seamRowFromDiff(paths, seam) {
478
493
  if (seam.length === 0 || paths.length === 0) {
@@ -486,8 +501,8 @@ export function seamRowFromDiff(paths, seam) {
486
501
  const evidence = `strayed: ${outside.length} path${outside.length === 1 ? '' : 's'} outside the seam`;
487
502
  const only = outside[0];
488
503
  return outside.length === 1 && only !== undefined
489
- ? { verdict: 'failing', word: 'strayed', evidence, pointer: only }
490
- : { verdict: 'failing', word: 'strayed', evidence, items: outside };
504
+ ? { verdict: 'advisory', word: 'strayed', evidence, pointer: only }
505
+ : { verdict: 'advisory', word: 'strayed', evidence, items: outside };
491
506
  }
492
507
  /**
493
508
  * Sum numstat entries into the diff row's three counts.
@@ -225,7 +225,9 @@ function resolveStep(root, args) {
225
225
  * step's seam, or '' when it held.
226
226
  *
227
227
  * Guidance, not a gate: the checkpoint captures the drift and says so, and the
228
- * bumped stat puts a `staged outside the seam` rung under the Verdict. The seam
228
+ * bumped stat puts a `seam strayed` rung under the Verdict, the same rung the
229
+ * pause's measured seam row gave it, since the row vanishes once the tree is
230
+ * committed and the stat is what carries the stray past that point. The seam
229
231
  * (the step's edit grant: exact paths or `dir/` prefixes) comes from the
230
232
  * in-flight SEAM file when a build is live, else the step's declared seam in
231
233
  * intent.md. Plumbbob's own artifact plane is whitelisted inside `scopeDrift`,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "plumbbob",
3
- "version": "0.11.1",
3
+ "version": "0.11.2",
4
4
  "description": "Attention-first build process: 14 skills + a CLI that keep you the decider — guidance on the work, a latch on the record.",
5
5
  "keywords": [
6
6
  "claude-code",