capdag 1.248.10 → 1.255.27

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/README.md CHANGED
@@ -1,131 +1,64 @@
1
- # Cap URN - JavaScript Implementation
1
+ # CapDAG for JavaScript
2
2
 
3
- JavaScript implementation of Cap URN (Capability Uniform Resource Names), built on [Tagged URN](https://github.com/machinefabric/tagged-urn-js).
3
+ This public package is CapDAG's JavaScript planning and notation mirror. Use it
4
+ in browsers or Node.js for Tagged, Media, and Cap URNs, capability definitions,
5
+ dispatch, Machine Notation, planning, and graph rendering.
4
6
 
5
- ## Features
7
+ JavaScript intentionally does not implement the cartridge runtime, host, relay,
8
+ or Bifaci process surface. That boundary is part of the package design, not an
9
+ unreported parity gap. Rust remains the behavioral reference for shared
10
+ features.
6
11
 
7
- - **Required Direction Specifiers** - `in`/`out` tags for input/output media types
8
- - **Media URN Validation** - Validates direction spec values are valid Media URNs
9
- - **Special Pattern Values** - `*` (must-have-any), `?` (unspecified), `!` (must-not-have)
10
- - **Graded Specificity** - Exact values score higher than wildcards
11
- - **Cross-Language Compatible** - Identical behavior to Rust, Go, and Objective-C implementations
12
- - **Production Ready** - No fallbacks, fails hard on invalid input
13
-
14
- ## Installation
12
+ ## Install the package
15
13
 
16
14
  ```bash
17
15
  npm install capdag
18
16
  ```
19
17
 
20
- ## Quick Start
18
+ Node.js 14 or newer is required by the package manifest.
21
19
 
22
- ```javascript
23
- const { CapUrn, CapUrnBuilder, CapMatcher } = require('capdag');
20
+ ## Parse and build Cap URNs
24
21
 
25
- // Create from string (with required direction specifiers)
26
- const cap = CapUrn.fromString('cap:in="media:binary";extract;out="media:object"');
27
- console.log(cap.toString());
22
+ ```javascript
23
+ const { CapUrn, CapUrnBuilder } = require("capdag");
28
24
 
29
- // Use builder pattern
25
+ const parsed = CapUrn.fromString(
26
+ 'cap:disbind;in="media:ext=pdf";out="media:enc=utf-8;page"'
27
+ );
30
28
  const built = new CapUrnBuilder()
31
- .inSpec('media:void')
32
- .outSpec('media:object')
33
- .tag('op', 'generate')
34
- .tag('target', 'thumbnail')
35
- .build();
36
-
37
- // Matching
38
- const request = CapUrn.fromString('cap:in="media:binary";extract;out="media:object"');
39
- console.log(cap.accepts(request)); // true
40
-
41
- // Find best match by specificity
42
- const caps = [
43
- CapUrn.fromString('cap:in=*;extract;out=*'),
44
- CapUrn.fromString('cap:in="media:binary";extract;out="media:object"'),
45
- CapUrn.fromString('cap:ext=pdf;in="media:binary";extract;out="media:object"')
46
- ];
47
- const best = CapMatcher.findBestMatch(caps, request);
48
- console.log(best.toString()); // Most specific match
49
- ```
50
-
51
- ## API Reference
52
-
53
- ### CapUrn Class
54
-
55
- #### Static Methods
56
- - `CapUrn.fromString(s)` - Parse Cap URN from string
57
- - Throws `CapUrnError` on invalid format or missing direction specifiers
58
-
59
- #### Instance Methods
60
- - `toString()` - Get canonical string representation
61
- - `getTag(key)` - Get tag value (case-insensitive)
62
- - `getInSpec()` - Get input media type
63
- - `getOutSpec()` - Get output media type
64
- - `hasTag(key, value)` - Check if tag exists with value
65
- - `withTag(key, value)` - Add/update tag (returns new instance)
66
- - `withoutTag(key)` - Remove tag (returns new instance)
67
- - `accepts(request)` - Check if this cap (as pattern) accepts a request
68
- - `specificity()` - Get specificity score for matching
69
- - `isMoreSpecificThan(other)` - Compare specificity
70
- - `equals(other)` - Check equality
71
-
72
- ### CapUrnBuilder Class
73
-
74
- Fluent builder for constructing Cap URNs:
75
-
76
- ```javascript
77
- const cap = new CapUrnBuilder()
78
- .inSpec('media:binary')
79
- .outSpec('media:object')
80
- .tag('op', 'extract')
81
- .tag('target', 'metadata')
29
+ .inSpec("media:ext=pdf")
30
+ .outSpec("media:enc=utf-8;page")
31
+ .marker("disbind")
82
32
  .build();
83
- ```
84
33
 
85
- ### CapMatcher Class
86
-
87
- Utility for matching sets of caps:
88
-
89
- - `CapMatcher.findBestMatch(caps, request)` - Find most specific match
90
- - `CapMatcher.findAllMatches(caps, request)` - Find all matches (sorted by specificity)
91
-
92
- ### Error Handling
93
-
94
- ```javascript
95
- const { CapUrnError, ErrorCodes } = require('capdag');
96
-
97
- try {
98
- const cap = CapUrn.fromString('cap:extract;in=media:;out=media:'); // Missing in/out
99
- } catch (error) {
100
- if (error instanceof CapUrnError) {
101
- console.log(`Error code: ${error.code}`); // MISSING_IN_SPEC
102
- }
103
- }
34
+ console.log(parsed.toString() === built.toString());
104
35
  ```
105
36
 
106
- Cap-specific error codes:
107
- - `ErrorCodes.MISSING_IN_SPEC` - Missing required `in` tag
108
- - `ErrorCodes.MISSING_OUT_SPEC` - Missing required `out` tag
109
- - `ErrorCodes.INVALID_MEDIA_URN` - Invalid Media URN in direction spec
37
+ Treat URNs as opaque parsed values. Use the package's predicates for
38
+ equivalence, conformance, dispatch, and ranking instead of string surgery.
110
39
 
111
- For base Tagged URN error codes, see [Tagged URN documentation](https://github.com/machinefabric/tagged-urn-js).
40
+ ## Find the relevant API
112
41
 
113
- ## Documentation
42
+ - `capdag.js` provides URNs, definitions, dispatch, and matching.
43
+ - `machine-parser.js` is generated from `machine.pegjs`.
44
+ - `planner.js` provides planning and Machine Notation structures.
45
+ - `cap-fab-renderer.js` and the browser build support graph presentation.
46
+ - [`RULES.md`](RULES.md) records package-specific construction rules.
114
47
 
115
- - [RULES.md](./RULES.md) - Cap-specific rules
116
- - [Tagged URN RULES.md](https://github.com/machinefabric/tagged-urn-js/blob/main/RULES.md) - Base format rules (case, quoting, wildcards, etc.)
48
+ The normative semantics and terminology live in the
49
+ [CapDAG specification](https://github.com/machinefabric/capdag/blob/main/docs/01-overview.md). Source comments and
50
+ exports are the JavaScript API reference.
117
51
 
118
- ## Testing
52
+ ## Build and verify changes
119
53
 
120
54
  ```bash
55
+ npm run build:parser
121
56
  npm test
122
57
  ```
123
58
 
124
- ## Cross-Language Compatibility
59
+ `npm test` runs the parser build first. Shared behavior changes require the
60
+ applicable reference test with the same substantive number and assertions.
125
61
 
126
- This JavaScript implementation produces identical results to:
127
- - [Rust reference implementation](https://github.com/machinefabric/capdag)
128
- - [Go implementation](https://github.com/machinefabric/capdag-go)
129
- - [Objective-C implementation](https://github.com/machinefabric/capdag-objc)
62
+ ## License
130
63
 
131
- All implementations pass the same test cases and follow identical rules.
64
+ MIT
@@ -2234,8 +2234,7 @@ function buildRunGraphData(data) {
2234
2234
  };
2235
2235
  }
2236
2236
 
2237
- // Expanding. The plan mirrors the working
2238
- // `machfab-mac/.scrap/working_graph/.../RunGraphViewer.html`:
2237
+ // Expanding. The plan uses the renderer's established fan-out layout:
2239
2238
  //
2240
2239
  // pre-foreach backbone ... → [anchor]
2241
2240
  // │
package/capdag.js CHANGED
@@ -5603,9 +5603,12 @@ function slugForSync(registryUrl) {
5603
5603
  }
5604
5604
 
5605
5605
  /**
5606
- * How a cartridge was installed. Pure metadata — never consulted for any host
5607
- * or engine routing decision. Mirrors Rust CartridgeInstallSource; the
5608
- * on-disk JSON uses snake_case values.
5606
+ * How a cartridge was installed. Exactly ONE value is semantic: BUNDLE
5607
+ * selects the bundled-cartridge integrity path at discovery. Every other
5608
+ * value is provenance telemetry, and the vocabulary GROWS as installers do —
5609
+ * so an unrecognized spelling is preserved verbatim on the record and
5610
+ * round-trips, never failing the cartridge.json parse. Mirrors Rust
5611
+ * CartridgeInstallSource; the on-disk JSON uses snake_case values.
5609
5612
  */
5610
5613
  const CartridgeInstallSource = Object.freeze({
5611
5614
  REGISTRY: 'registry',
@@ -5744,10 +5747,12 @@ class CartridgeJson {
5744
5747
  }
5745
5748
  let installedFrom = null;
5746
5749
  if (obj.installed_from !== undefined && obj.installed_from !== null) {
5747
- const valid = Object.values(CartridgeInstallSource);
5748
- if (!valid.includes(obj.installed_from)) {
5749
- throw new CartridgeJsonError(CartridgeJsonErrorKind.INVALID_JSON, `cartridge.json unknown installed_from: ${obj.installed_from}`);
5750
+ if (typeof obj.installed_from !== 'string') {
5751
+ throw new CartridgeJsonError(CartridgeJsonErrorKind.INVALID_JSON, 'cartridge.json installed_from must be a string');
5750
5752
  }
5753
+ // An unknown spelling is preserved VERBATIM: the provenance vocabulary
5754
+ // grows as installers do, and a telemetry hint must never fail the
5755
+ // parse and take the cartridge down with it. Only BUNDLE is semantic.
5751
5756
  installedFrom = obj.installed_from;
5752
5757
  }
5753
5758
  return new CartridgeJson({
@@ -6150,7 +6155,6 @@ function encodeHelloFrame() {
6150
6155
  ['max_reorder_buffer', BIFACI_DEFAULT_MAX_REORDER_BUFFER],
6151
6156
  ['initial_credit', BIFACI_DEFAULT_INITIAL_CREDIT],
6152
6157
  ['version', BIFACI_PROTOCOL_VERSION],
6153
- ['handler_capacity', 0],
6154
6158
  ],
6155
6159
  };
6156
6160
  const frame = {
@@ -6265,9 +6269,21 @@ function probeCartridgeCapGroups(entryPath) {
6265
6269
  finish(new Error(`cartridge ${entryPath} HELLO failed: meta.version ${metaVersion} does not match required version ${BIFACI_PROTOCOL_VERSION}`));
6266
6270
  return;
6267
6271
  }
6268
- const handlerCapacity = meta.get('handler_capacity');
6269
- if (!Number.isSafeInteger(handlerCapacity) || handlerCapacity < 0) {
6270
- finish(new Error(`cartridge ${entryPath} HELLO failed: missing required non-negative handler_capacity`));
6272
+ // The concurrency-pool state map is MANDATORY on a cartridge HELLO
6273
+ // (bifaci pools, protocol v4): JSON bytes under meta key "pools". A
6274
+ // missing or malformed map is a protocol violation, never a default.
6275
+ const poolsVal = meta.get('pools');
6276
+ if (!poolsVal || poolsVal.__bytes === undefined) {
6277
+ finish(new Error(`cartridge ${entryPath} HELLO failed: missing required concurrency-pool state map`));
6278
+ return;
6279
+ }
6280
+ try {
6281
+ const poolStates = JSON.parse(Buffer.from(poolsVal.__bytes).toString('utf8'));
6282
+ if (poolStates === null || typeof poolStates !== 'object' || Array.isArray(poolStates)) {
6283
+ throw new Error('pool-state map must be a JSON object');
6284
+ }
6285
+ } catch (e) {
6286
+ finish(new Error(`cartridge ${entryPath} HELLO failed: malformed pool-state map: ${e.message}`));
6271
6287
  return;
6272
6288
  }
6273
6289
  const manifestVal = meta.get('manifest');
package/capdag.test.js CHANGED
@@ -6965,6 +6965,40 @@ function assertThrowsPlanState(fn, message) {
6965
6965
 
6966
6966
  // TEST1450: a defaults-only request is AUTO with every knob at its default,
6967
6967
  // and the proto JSON carries the documented wire shape.
6968
+ // TEST1514: the provenance vocabulary grows with installers. A workspace
6969
+ // build install parses to its named value; a spelling this build does not
6970
+ // know parses, is preserved VERBATIM, round-trips, and is not BUNDLE (the
6971
+ // one semantic value) — an unknown telemetry hint can never fail the
6972
+ // cartridge.json parse and take the cartridge down with it.
6973
+ function test1514_installSourceVocabularyTolerance() {
6974
+ const base = {
6975
+ name: 'candlecartridge',
6976
+ version: '1.227.800',
6977
+ channel: 'nightly',
6978
+ registry_url: 'https://cartridges-staging.machinefabric.com/v1/manifest',
6979
+ entry: 'candlecartridge',
6980
+ installed_at: '2026-08-14T22:26:59Z',
6981
+ fabric_manifest_version: 4,
6982
+ };
6983
+ // A drifted installer's spelling is tolerated but NOT blessed: the
6984
+ // protocol's vocabulary is registry/dev/bundle/app_installer, and a
6985
+ // writer's mistake never becomes a named value.
6986
+ const built = CartridgeJson.fromObject({ ...base, installed_from: 'build' });
6987
+ assert(built.installedFrom === 'build',
6988
+ `build is preserved verbatim like any unknown, got ${built.installedFrom}`);
6989
+ assert(!Object.values(CartridgeInstallSource).includes('build'),
6990
+ 'build is not part of the protocol vocabulary');
6991
+
6992
+ const unknown = CartridgeJson.fromObject({ ...base, installed_from: 'quantum_courier' });
6993
+ assert(unknown.installedFrom === 'quantum_courier',
6994
+ `unknown spellings are preserved verbatim, got ${unknown.installedFrom}`);
6995
+ assert(unknown.installedFrom !== CartridgeInstallSource.BUNDLE,
6996
+ 'an unknown spelling is never the semantic bundle value');
6997
+ const rewritten = unknown.toObject ? unknown.toObject() : JSON.parse(JSON.stringify(unknown));
6998
+ assert((rewritten.installed_from || rewritten.installedFrom) === 'quantum_courier',
6999
+ 'unknown spellings round-trip');
7000
+ }
7001
+
6968
7002
  function test1450_planRequestDefaults() {
6969
7003
  const request = new plannerNS.PlanRequest({
6970
7004
  sources: [{ mediaUrn: 'media:ext=pdf', isSequence: false }],
@@ -7589,6 +7623,7 @@ async function runTests() {
7589
7623
 
7590
7624
  // planner.js: unified plan-space vocabulary
7591
7625
  console.log('--- planner.js ---');
7626
+ runTest('TEST1514: install_source_vocabulary_tolerance', test1514_installSourceVocabularyTolerance);
7592
7627
  runTest('TEST1450: plan_request_defaults', test1450_planRequestDefaults);
7593
7628
  runTest('TEST1451: plan_request_knob_validation', test1451_planRequestKnobValidation);
7594
7629
  runTest('TEST1452: knob_proto_round_trip', test1452_knobProtoRoundTrip);
package/package.json CHANGED
@@ -41,5 +41,5 @@
41
41
  "pretest": "npm run build:parser",
42
42
  "test": "node capdag.test.js"
43
43
  },
44
- "version": "1.248.10"
44
+ "version": "1.255.27"
45
45
  }