@brutalsystems/muster 0.9.1 → 0.9.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.
package/CANONICAL_ID.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Tin Can — Address Format
2
2
 
3
- > **Normative for `@brutalsystems/tincan` 1.6.0.**
3
+ > **Normative for `@brutalsystems/tincan` 1.9.2.**
4
4
  >
5
5
  > This describes what Tin Can does today, precisely enough for another tool to
6
6
  > produce addresses Tin Can will resolve. It is a write-down of shipped
@@ -140,6 +140,18 @@ The separator is `.` so that an address needs no shell quoting.
140
140
  `canonical_id` is always fully qualified, whether or not there is a collision.
141
141
  It is the form to record in logs and to pass between tools.
142
142
 
143
+ **Do not recover the suffix from a canonical id by string surgery.** Taking the
144
+ last dot-separated segment gave the three-character suffix before 1.0.0 and
145
+ gives the whole durable id now — `01a0b9b4-a33e-7ab1-80a0-bb715504a0fb`, not
146
+ `0fb`. A reimplementation that does this builds qualified addresses that look
147
+ right and match nothing, and the failure surfaces as `unknown`, which names a
148
+ missing peer rather than a malformed address. Reported by muster, where it made
149
+ every `slug.suffix` address fail silently until a test was written for it.
150
+
151
+ Derive the suffix from the **uuid**, with `suffixOf` — the last three hex
152
+ characters of the id with non-hex removed. The canonical form is an address to
153
+ pass along whole, not a record to parse fields out of.
154
+
143
155
  ## Collision
144
156
 
145
157
  A peer is suffixed in its **display** form when either:
@@ -370,3 +370,114 @@ rule it documents — refuse a prefix that ends at a segment boundary — fails
370
370
  new case *and* `resolve: unambiguous prefix resolves` together, in this copy.
371
371
  That pair failing together is the argument for Tin Can's decision to document
372
372
  the defect rather than change resolution, and it reproduces here.
373
+
374
+ ## Re-sync to Tin Can 1.7.0 — 2026-09-24
375
+
376
+ The copies are now from tag `v1.7.0`, commit
377
+ `f2aaeb20ea278c229afe955db59f69301fc6626f`.
378
+
379
+ | File | SHA-256 |
380
+ | --- | --- |
381
+ | `CANONICAL_ID.md` | `8d5e93894e5c43cc854330f7b64ebbdcc450649cfa910c8b4015edf2559125e7` |
382
+ | `test/fixtures/canonical-id.json` | `1db118b22484271932e7cde33c1c80b469563f18f2961532d6910d79ce1e4c3b` |
383
+
384
+ `tincan_version: 1.7.0`, still 40 cases: 8 slugify, 7 suffix, 12 assignment, 13
385
+ resolution. **No expected value moved and no case was added.** Diffed
386
+ `v1.6.0..v1.7.0` upstream before copying: `src/naming.ts` does not appear in the
387
+ diff at all, the fixture's only changed line is its `tincan_version`, and
388
+ `CANONICAL_ID.md` gains fourteen lines of warning with no normative change. So
389
+ `naming.ts` is untouched here and the contract suite is expected to stay 4/4
390
+ without it — this is a re-label plus a doc, not an address-format change.
391
+
392
+ What the doc gains is the hazard this repo hit and reported: recovering the
393
+ three-hex suffix by taking a canonical id's last dot-separated segment returned
394
+ the suffix before 1.0.0 and returns the whole uuid now, so every qualified
395
+ `slug.suffix` address resolves as `unknown` — a missing peer, not a malformed
396
+ address, which is why it stayed quiet here until a test was written for it.
397
+ Tin Can names Muster as where it was found. The rule is to derive the suffix
398
+ from the uuid via `suffixOf` and otherwise pass a canonical id along whole
399
+ rather than parse fields out of it.
400
+
401
+ **A re-sync touches three sites, not two.** Both Tin Can pins —
402
+ `RELEASING.md` and `.github/workflows/publish.yml` — plus the SHA-256 drift
403
+ hashes in `test/naming.test.ts` ("contract copies remain frozen"), which must
404
+ move whenever a copied file changes. The two pins are the ones handed down in
405
+ conversation; the hashes were found by grepping for the old version and the old
406
+ digests rather than by working from that list, so grep the repo instead of
407
+ trusting an enumeration. That advice earned itself twice over: this very
408
+ enumeration missed `README.md`, which carried a literal baseline of its own —
409
+ recorded below.
410
+
411
+ Moving only the first pin is what made v0.9.0 an inert tag that published
412
+ nothing. `test/workflow-npm-pin.test.ts` now fails when the two pins disagree,
413
+ or when the `publish.yml` pin and the fixture's `tincan_version` disagree, and
414
+ that guard was re-confirmed by mutation here rather than assumed: reverting
415
+ `publish.yml` alone to 1.6.0 fails both assertions, and restoring it passes
416
+ them. A stale drift hash fails `npm run check` on its own.
417
+
418
+ ### The pin sites became one derived value
419
+
420
+ Recording the fix rather than only the incident. The two Tin Can pins no longer
421
+ restate a version; both compute it from this fixture's `tincan_version`. That
422
+ field is the single place saying which Tin Can the vendored copies describe, so
423
+ a pin can no longer lag it — the v0.9.0 failure class is closed structurally
424
+ instead of guarded after the fact.
425
+
426
+ The guard that replaced the old agreement tests asserts the derivation
427
+ expression itself, not the word `tincan_version`. The first version of it
428
+ checked for the word and **passed against a `publish.yml` whose command had
429
+ been mutated to `ver="1.6.0"`**, because the prose explaining the derivation
430
+ contains that word too. It was caught by running the mutation rather than by
431
+ reading the test. A guard that cannot fail is the thing this document exists to
432
+ prevent, so the failure is written down next to the fix.
433
+
434
+ ### README.md was a fourth site, and had already gone stale
435
+
436
+ The enumeration above missed it. `README.md`'s Verification section named its own
437
+ baseline — **Tin Can 0.6.4** in prose, and `@brutalsystems/tincan@0.6.4` in a
438
+ copy-paste command — and had drifted unnoticed while the vendored copies moved to
439
+ 1.6.0 and then 1.9.2. Nothing failed, because it gates nothing: it is
440
+ instructions for a human, so the cost was silence rather than an inert tag.
441
+
442
+ That makes it worse than a failing pin, not better. Anyone following the README
443
+ installed a Tin Can four minors behind the one the fixture describes and watched
444
+ the contract suite pass 4/4 — which reads as confirmation that the contract holds
445
+ at a version nobody vendored.
446
+
447
+ Fixed the same way as the other two sites: the command derives `ver` from the
448
+ fixture, and the prose points at `tincan_version` rather than naming a release.
449
+ `test/workflow-npm-pin.test.ts` now includes `README.md` in the derivation loop,
450
+ and adds one assertion that its Verification section names no Tin Can version in
451
+ prose at all, because prose restates a pin as easily as a command does. Both were
452
+ watched failing against the stale README before anything was changed — the
453
+ literal-pin assertion on the command, and `expected 'Tin Can 0.6.4' to be
454
+ undefined` on the prose — and the derived command was then extracted from the
455
+ README and run end to end, installing 1.9.2 and passing the contract suite 4/4.
456
+
457
+ The prose assertion is scoped to `## Verification` on purpose. Elsewhere the
458
+ README records what was observed at a particular Tin Can — "Tin Can 0.6.0
459
+ delivers over v1, so nothing here depends on the v2 path" — which is a historical
460
+ claim and stays pinned to its version deliberately. A whole-file regex would fail
461
+ on those and teach the next person to delete the guard.
462
+
463
+ ## Re-sync to Tin Can 1.9.2 — 2026-09-25
464
+
465
+ Copies are from tag `v1.9.2`.
466
+
467
+ | File | SHA-256 |
468
+ | --- | --- |
469
+ | `CANONICAL_ID.md` | `6e0dde03154956a480ae59f4d31b727ecc5a9e735c185fed6e4445f2574263a9` |
470
+ | `test/fixtures/canonical-id.json` | `b91406e068f6bec18629a4d2b9e91bc4d2e5a0487e4b6b4534fd5ba37c7f617a` |
471
+
472
+ `tincan_version: 1.9.2`, still 40 cases. Diffing `v1.7.0..v1.9.2` upstream, the
473
+ ONLY change across all three contract files is the version string in two lines —
474
+ `naming.ts` does not appear, and no fixture case or expected value moved. 1.8.0
475
+ (log chaining, arrival record), 1.9.0 (version reporting in `peers`), 1.9.1 and
476
+ 1.9.2 (registration drift) do not touch the address format. Verified here rather
477
+ than taken from upstream's word: they explicitly said not to treat their summary
478
+ as a re-copy signal.
479
+
480
+ **This re-sync needed no pin edit.** The pins derive from `tincan_version`, so
481
+ updating the fixture moved CI on its own — the first cut where the failure class
482
+ that produced v0.9.0 had nothing to act on. The drift hashes still moved, which
483
+ is the third site behaving exactly as documented above.
package/README.md CHANGED
@@ -1024,19 +1024,25 @@ The ordinary suite requires tmux, node-pty, POSIX `ps`/`lsof`, and Python 3 for
1024
1024
  real file locks in the fake Codex executable. It uses isolated runtime homes and
1025
1025
  no model APIs. It skips the four explicitly invoked compatibility cases.
1026
1026
 
1027
- The verified contract baseline is **Tin Can 0.6.4**. The suite spawns an installed binary as an MCP
1028
- subprocess, compares durable IDs, and verifies delivery to fake runtimes through
1029
- both terminal hosts. A missing binary or missing durable field fails the test.
1030
- For reproducible verification, install that exact release outside Muster:
1027
+ The verified contract baseline is the Tin Can named by `tincan_version` in the
1028
+ frozen fixture, `test/fixtures/canonical-id.json`. That field is the single place
1029
+ recording which release the vendored copies describe, and both `RELEASING.md` and
1030
+ `publish.yml` derive their pin from it. The suite spawns an installed binary as
1031
+ an MCP subprocess, compares durable IDs, and verifies delivery to fake runtimes
1032
+ through both terminal hosts. A missing binary or missing durable field fails the
1033
+ test. For reproducible verification, install that exact release outside Muster —
1034
+ derived here too, rather than typed, so this command cannot name a release the
1035
+ fixture has moved past:
1031
1036
 
1032
1037
  ```sh
1033
1038
  contract_dir=$(mktemp -d)
1034
- npm install --prefix "$contract_dir" --no-save @brutalsystems/tincan@0.6.4
1039
+ ver=$(node -p "require('./test/fixtures/canonical-id.json').tincan_version")
1040
+ npm install --prefix "$contract_dir" --no-save "@brutalsystems/tincan@$ver"
1035
1041
  MUSTER_TINCAN_BIN="$contract_dir/node_modules/.bin/tincan" npm run test:contract
1036
1042
  ```
1037
1043
 
1038
- Verification uses the published 0.6.4 release installed in an isolated
1039
- temporary directory. No Tin Can source edits are made.
1044
+ Verification uses that published release installed in an isolated temporary
1045
+ directory. No Tin Can source edits are made.
1040
1046
  Fixture version metadata alone does not indicate address-format drift: compare
1041
1047
  the case arrays. Those arrays cover naming only, not peer-list membership or
1042
1048
  state semantics. Upgrades require separate compatibility verification; passing
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@brutalsystems/muster",
3
- "version": "0.9.1",
3
+ "version": "0.9.2",
4
4
  "description": "Launch instructed, reachable local agent sessions",
5
5
  "type": "module",
6
6
  "engines": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "$comment": "FROZEN. Describes @brutalsystems/tincan address behaviour as shipped. Adding cases is fine; changing an expected value means the address format changed - see CANONICAL_ID.md, 'Changing this format'.",
3
- "tincan_version": "1.6.0",
3
+ "tincan_version": "1.9.2",
4
4
  "spec": "CANONICAL_ID.md",
5
5
  "slugify": [
6
6
  {