wowbagger 0.1.0-alpha.11 → 0.1.0-alpha.12

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.
package/CHANGELOG.md CHANGED
@@ -7,6 +7,25 @@ consolidation. The first tagged release inherits this file.
7
7
 
8
8
  ## Unreleased
9
9
 
10
+ ## 0.1.0-alpha.12 - 2026-08-28
11
+
12
+ ### Fixed
13
+
14
+ - **Out-of-protocol local states remain global reconciliation barriers.**
15
+ Alpha.11 could misclassify an unknown committed revision, an authorized
16
+ working-tree predecessor over an unknown `HEAD`, or a working-tree deletion
17
+ over an authorized `HEAD` as advisory sibling synchronization when another
18
+ worktree owned the expected revision. `claim-verify` still failed, but an
19
+ unrelated mutation could proceed through the documented global barrier.
20
+ Alpha.12 classifies local state before owner and target scope, while genuine
21
+ authorized sibling predecessors remain target-scoped synchronization.
22
+ - **Windows report path resolution preserves the read-failure error class.**
23
+ Windows can report `ENOENT` where POSIX reports `ENOTDIR` when an output path
24
+ descends through a regular file. Report generation now recognizes that
25
+ non-directory ancestor and returns `report-read-failed` with
26
+ `resolve-output-path` and `ENOTDIR` before publication, instead of surfacing
27
+ `report-write-failed` with `EEXIST`.
28
+
10
29
  ## 0.1.0-alpha.11 - 2026-08-27
11
30
 
12
31
  ### Fixed
package/README.md CHANGED
@@ -30,8 +30,8 @@ agent to use those guarantees instead of hand-editing your Markdown.
30
30
 
31
31
  **Start here:** [install the core and set up a ledger](#start-here).
32
32
 
33
- > **Status: alpha, published, and self-hosted.** `0.1.0-alpha.11` is on npm under
34
- > the `next` tag and on this repository's `v0.1.0-alpha.11` tag. It is the
33
+ > **Status: alpha, published, and self-hosted.** `0.1.0-alpha.12` is on npm under
34
+ > the `next` tag and on this repository's `v0.1.0-alpha.12` tag. It is the
35
35
  > version this repository runs its own backlog on. The API is not frozen and the
36
36
  > version will move before a stable release.
37
37
  >
@@ -77,7 +77,7 @@ Wowbagger is the core authority for a Git-native work ledger. Use it instead
77
77
  of editing ledger Markdown by hand.
78
78
 
79
79
  ```sh
80
- wowbagger --version # require 0.1.0-alpha.11
80
+ wowbagger --version # require 0.1.0-alpha.12
81
81
  wowbagger capabilities --json # require contract_version: 5
82
82
  wowbagger validate --ledger ledger --json
83
83
  wowbagger ready --ledger ledger --as-of YYYY-MM-DD --json
@@ -103,10 +103,10 @@ cooperating writers; they are not exclusive locks.
103
103
  Install the core CLI, then verify it. The core requires Node.js 20 or later:
104
104
 
105
105
  ```sh
106
- npm install -g wowbagger@0.1.0-alpha.11 # exact plugin-matched release
106
+ npm install -g wowbagger@0.1.0-alpha.12 # exact plugin-matched release
107
107
  # or, from this release's Git tag:
108
- # npm install -g github:lstutzman/wowbagger#v0.1.0-alpha.11
109
- wowbagger --version # 0.1.0-alpha.11
108
+ # npm install -g github:lstutzman/wowbagger#v0.1.0-alpha.12
109
+ wowbagger --version # 0.1.0-alpha.12
110
110
  wowbagger capabilities --json # must report contract_version: 5
111
111
  ```
112
112
 
@@ -325,7 +325,7 @@ two supported install routes:
325
325
  registry requires a `latest` tag), so a bare install resolves to the same
326
326
  bytes.
327
327
  - **git tag** —
328
- `npm install -g github:lstutzman/wowbagger#v0.1.0-alpha.11` installs this
328
+ `npm install -g github:lstutzman/wowbagger#v0.1.0-alpha.12` installs this
329
329
  release. Installing at a ref installs the core and every adapter that ref
330
330
  carries.
331
331
 
@@ -397,7 +397,7 @@ Upgrade the pieces you installed:
397
397
 
398
398
  ```sh
399
399
  npm install -g wowbagger@next # public npm registry
400
- npm install -g github:lstutzman/wowbagger#v0.1.0-alpha.11 # immutable Git release
400
+ npm install -g github:lstutzman/wowbagger#v0.1.0-alpha.12 # immutable Git release
401
401
  git pull && npm ci # or: a direct checkout
402
402
  ```
403
403
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wowbagger",
3
- "version": "0.1.0-alpha.11",
3
+ "version": "0.1.0-alpha.12",
4
4
  "description": "Git-native work ledger for coding agents: deterministic ready queues, guarded CAS mutations, claims and fencing, and self-contained HTML reports.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -14,7 +14,7 @@ publish something.
14
14
  Install the core separately before using this skill:
15
15
 
16
16
  ```sh
17
- npm install -g wowbagger@0.1.0-alpha.11
17
+ npm install -g wowbagger@0.1.0-alpha.12
18
18
  ```
19
19
 
20
20
  The core requires Node.js 20 or later. This plugin ships only agent
@@ -34,9 +34,9 @@ wowbagger capabilities --json
34
34
 
35
35
  Read the plain distribution version from the first command and the top-level
36
36
  `contract_version` from the second. **This skill requires distribution version
37
- `0.1.0-alpha.11` and core `contract_version: 5`.**
37
+ `0.1.0-alpha.12` and core `contract_version: 5`.**
38
38
 
39
- The distribution pin names the published `0.1.0-alpha.11` release; the cut that
39
+ The distribution pin names the published `0.1.0-alpha.12` release; the cut that
40
40
  publishes core `contract_version: 5` moves it. Earlier cores report
41
41
  `contract_version: 3` or lower and lack behavior this skill requires, including
42
42
  the bounded item source, so the version check refuses them. Do not soften
@@ -773,6 +773,20 @@ async function reconciliationDiagnosis({
773
773
  workingTreeChanged,
774
774
  }) {
775
775
  const pathLabel = expectedPath ?? 'the item path';
776
+ // Two remedies, both named, in the order that makes the cost obvious. The
777
+ // field report behind item #113 read the single restore sentence as the only
778
+ // way out and discarded reviewed, merged work to obey it.
779
+ const unauthorizedRevision = {
780
+ reason: 'unauthorized-revision',
781
+ ...(expectedPath ? { expected_path: expectedPath } : {}),
782
+ remediation: `Restore the authorized revision at ${pathLabel}, then run claim-verify; that discards the edit. Or adopt the committed revision of ${pathLabel} with claim-adopt, then run claim-verify; that keeps the edit.`,
783
+ };
784
+ const hasOutOfProtocolLocalState = (
785
+ (actualRevision !== null && !authorizedRevisions.has(actualRevision))
786
+ || (headRevision !== null && !authorizedRevisions.has(headRevision))
787
+ || (actualRevision === null && headRevision !== null)
788
+ );
789
+ if (hasOutOfProtocolLocalState) return unauthorizedRevision;
776
790
  let expectedOwner = null;
777
791
  if (headRevision !== null && actualRevision === headRevision
778
792
  && headRevision !== expectedRevision) {
@@ -828,14 +842,7 @@ async function reconciliationDiagnosis({
828
842
  };
829
843
  }
830
844
  }
831
- // Two remedies, both named, in the order that makes the cost obvious. The
832
- // field report behind item #113 read the single restore sentence as the only
833
- // way out and discarded reviewed, merged work to obey it.
834
- return {
835
- reason: 'unauthorized-revision',
836
- ...(expectedPath ? { expected_path: expectedPath } : {}),
837
- remediation: `Restore the authorized revision at ${pathLabel}, then run claim-verify; that discards the edit. Or adopt the committed revision of ${pathLabel} with claim-adopt, then run claim-verify; that keeps the edit.`,
838
- };
845
+ return unauthorizedRevision;
839
846
  }
840
847
 
841
848
  function activePublicationMismatch(entries, record, actualRevision, observedAt) {
package/src/report.js CHANGED
@@ -1,4 +1,4 @@
1
- import { mkdir, open, readFile, realpath, rename, rm } from 'node:fs/promises';
1
+ import { mkdir, open, readFile, realpath, rename, rm, stat } from 'node:fs/promises';
2
2
  import path from 'node:path';
3
3
  import { projectReadiness } from './ready.js';
4
4
  import { buildAttention } from './report-attention.js';
@@ -502,7 +502,16 @@ async function resolvePhysicalPath(targetPath) {
502
502
 
503
503
  while (true) {
504
504
  try {
505
- return path.join(await realpath(existingPath), ...missingSegments.reverse());
505
+ const resolvedPath = await realpath(existingPath);
506
+ // Windows realpath reports ENOENT, not ENOTDIR, when a path component
507
+ // is a regular file, so the walk can land on a file that still has
508
+ // segments missing below it. Restate that as the ENOTDIR POSIX raises.
509
+ if (missingSegments.length > 0 && !(await stat(resolvedPath)).isDirectory()) {
510
+ const notADirectory = new Error(`ENOTDIR: not a directory, realpath '${targetPath}'`);
511
+ notADirectory.code = 'ENOTDIR';
512
+ throw notADirectory;
513
+ }
514
+ return path.join(resolvedPath, ...missingSegments.reverse());
506
515
  } catch (error) {
507
516
  if (error?.code !== 'ENOENT') {
508
517
  throw error;