@beehexa/hexasync-template-model 2608.15.1 → 2608.20.18

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,368 +0,0 @@
1
- /**
2
- * Which properties name another component — measured, not assumed (Stories 3.4 and 3.7).
3
- *
4
- * This list was originally guessed from what the collections are called, and the guess was wrong
5
- * in both directions. It is now derived from the corpus: every `*Id` / `*Ids` property in nine
6
- * real projects was resolved against the effective graph and kept only if its values are actually
7
- * component ids. The measured figures are recorded here because a list like this decays silently
8
- * — a property added next year will not announce itself — and the next person needs to know how
9
- * to re-derive it rather than how to guess again.
10
- *
11
- * Resolution rates, measured over real projects (hits / occurrences):
12
- *
13
- * taskId 651/651 100% metricId 0/651 0%
14
- * connectorId 413/413 100% providerId 0/27 0%
15
- * connectionId 284/284 100% columnIds 0/11 0%
16
- * entityId 115/115 100% credentialId 0/5 0%
17
- * objectIds 90/90 100% profileId 0/5 0%
18
- * targetId 59/59 100% systemId 0/4 0%
19
- * fromConnectionId 54/54 100% integrationAppId 0/4 0%
20
- * objectId 50/50 100% itemIds 0/3 0%
21
- * object_id 13/13 100%
22
- * pusherId 5/5 100%
23
- * tableId 4/4 100%
24
- * pullerId 2/2 100%
25
- *
26
- * Two findings worth stating plainly, because both contradict what was written down before:
27
- *
28
- * 1. **`taskId` is real, and is the most-used reference property in the corpus.** Story 3.7's AC
29
- * calls it "the ideation document's illustrative `taskId`, which does not exist" — that is
30
- * false. It appears 291 times in authored partials and resolves 651/651. The AC's underlying
31
- * instruction — key these to REAL property names — is right, and following it is what turned
32
- * up the error in its own example.
33
- * 2. **`validationId`, `transformationId`, `pullerIds` and `pusherIds` were invented** from the
34
- * collection names and have zero authored occurrences. Removed. `pullerId` was on the same
35
- * guessed list but turned out to be real (2/2), so it is kept — on the measurement, not on
36
- * the fact that a `pullers` collection exists.
37
- *
38
- * The values are often COMPOSE-TIME TOKENS — `taskId: "**Sapo_Orders_Task_Id**"` — and they
39
- * resolve because the graph keys components in token form (Story 3.1). Keying on substituted
40
- * values would have made every one of these references dangle.
41
- */
42
- /**
43
- * CORRECTED 2026-08-02, and the correction is about METHOD, not about three names.
44
- *
45
- * The resolution rates in the table above were measured by asking *"is this value some
46
- * component's id?"* — never *"does it point into the collection we claim?"*. Three consequences,
47
- * each of which shipped:
48
- *
49
- * 1. **`connectionId` and `fromConnectionId` pointed at `connections`, a collection that does
50
- * not exist.** Corpus-wide: **0** authored files declare `connections:`, **281** declare
51
- * `connectors:`, and its ids are exactly the `**…ConnectionId**` tokens these properties
52
- * hold. `connectionId`, `fromConnectionId` and `connectorId` are three spellings of one
53
- * target: `connectors[*].id`. A method that only checked "is an id" scored the wrong
54
- * collection at 100%.
55
- * 2. **`entityId` and `targetId` have no fixed collection — it comes from a SIBLING.** Measured
56
- * `entityType`: `SELF` 261 · `TASK` 118 · `PROFILE` 9. Measured `targetType`: `PULLER` 144 ·
57
- * `SCHEDULER` 105 · `REPORT` 44 · `SCHEMA` 43. `entityType: SELF` means "this task" and
58
- * carries no `entityId` at all. Absent, the type defaults to Task. A single `collection` field
59
- * cannot express this, which is why both were left collection-less — and a collection-less
60
- * entry matched a component in ANY collection and reported it resolved.
61
- * 3. **They resolve only in `**Token**` form.** Authored value shapes: `entityId` 175 token /
62
- * 1 raw UUID, `targetId` 151 / 0. The rule is not about volume — it is that the graph keys
63
- * components in TOKEN form (FR-45), so a raw UUID cannot match a component however it is
64
- * spelled. Reporting it as an unresolved reference would be noise; declining says the true
65
- * thing, and is a different answer from "a reference that does not resolve".
66
- *
67
- * CORRECTED 2026-08-03. This first read "178 token-form vs 268 raw UUID … 437 legitimate
68
- * authored values" — measured over a population that included GENERATED `output.yaml`, where
69
- * compose has already substituted each token for the real id. The index never reads those
70
- * files, so those values were never at risk. The mistake is the same one this whole note is
71
- * about: a count that did not say precisely enough what it was counting.
72
- *
73
- * The lesson generalises: a reference is a property, a target collection AND a value shape. Any
74
- * future re-derivation must assert all three, or it will score a wrong answer at 100% again.
75
- */
76
- /**
77
- * Values that are `**Token**` form — the only shape a conditional reference resolves in.
78
- *
79
- * TRIMMED, as of the Epic 2 review. It was not, while a second copy of this predicate 350 lines below was — so
80
- * a quoted `" **Token** "` was a token to one and a literal to the other. One definition, one answer.
81
- */
82
- const TOKEN_FORM = /^\*\*[^*]+\*\*$/;
83
- export const isTokenForm = (value) => TOKEN_FORM.test(value.trim());
84
- /** `entityType` → the collection an `entityId` beside it points into. */
85
- const ENTITY_TYPE_TARGETS = new Map([
86
- ['TASK', 'objects'],
87
- // "this task" — the entity IS the enclosing one, so there is no id to resolve.
88
- ['SELF', undefined],
89
- // A profile is not a template collection; the id is resolved outside the project.
90
- ['PROFILE', undefined],
91
- ]);
92
- /** `targetType` → the collection a `targetId` beside it points into. */
93
- const TARGET_TYPE_TARGETS = new Map([
94
- ['PULLER', 'pullers'],
95
- ['REPORT', 'reports'],
96
- ['SCHEMA', 'schemas'],
97
- ['SCHEDULER', 'startupTasks'],
98
- ]);
99
- export const REFERENCE_PROPERTY_LIST = [
100
- { property: 'taskId', collection: 'objects' },
101
- { property: 'objectId', collection: 'objects' },
102
- { property: 'object_id', collection: 'objects' },
103
- { property: 'objectIds', collection: 'objects' },
104
- { property: 'pusherId', collection: 'pushers' },
105
- { property: 'pullerId', collection: 'pullers' },
106
- { property: 'tableId', collection: 'tables' },
107
- /**
108
- * ADDED 2026-08-05, on measurement. A dependency names the Task it waits on with `dependedOn`.
109
- *
110
- * It was missing, and the omission was invisible because nothing asked for it: **910 authored
111
- * occurrences across 665 files**, of which **271 of 272 (99.6%) resolve to a Task** when measured
112
- * against composed graphs for all 33 buildable corpus projects. That is the same standard
113
- * `NON_REFERENCE_ID_PROPERTIES` below applies in the other direction — a property measured at 0%
114
- * resolution is not a reference, and one measured at 99.6% plainly is.
115
- *
116
- * The single miss is a REAL broken reference, in `001-projects/elly`: a `dependedOn` naming
117
- * `**SapoProductPuller**`, a token that resolves to nothing and, by its name, aims at a puller
118
- * where a Task belongs. Until now no validation, Find References or impact query could see it,
119
- * because this row did not exist.
120
- */
121
- { property: 'dependedOn', collection: 'objects' },
122
- // One target, three spellings. See the CORRECTED note above.
123
- { property: 'connectionId', collection: 'connectors' },
124
- { property: 'fromConnectionId', collection: 'connectors' },
125
- // ...except on a `connectors[]` entry, where it is that connection's own platform identity rather
126
- // than a reference to one. See `opaqueInCollections` on `ReferenceProperty`.
127
- {
128
- property: 'connectorId',
129
- collection: 'connectors',
130
- opaqueInCollections: ['connectors'],
131
- },
132
- {
133
- property: 'entityId',
134
- tokenFormOnly: true,
135
- discriminator: {
136
- siblings: ['entityType'],
137
- byValue: ENTITY_TYPE_TARGETS,
138
- fallback: 'objects',
139
- },
140
- },
141
- {
142
- property: 'targetId',
143
- tokenFormOnly: true,
144
- discriminator: {
145
- // `targetType` decides; `entityType` is the fallback discriminator where the block carries
146
- // one instead, and a Task is the default when neither is written.
147
- siblings: ['targetType', 'entityType'],
148
- byValue: new Map([...TARGET_TYPE_TARGETS, ...ENTITY_TYPE_TARGETS]),
149
- fallback: 'objects',
150
- },
151
- },
152
- ];
153
- /**
154
- * Resolve what a reference property means beside its siblings.
155
- *
156
- * Returns `undefined` when this property/value/context is NOT a component reference — a raw UUID
157
- * in `entityId`, or `entityType: SELF`. That is a distinct answer from "a reference that does not
158
- * resolve", and collapsing the two is what puts diagnostics on correct files.
159
- */
160
- export function resolveReferenceKind(property, value, siblings,
161
- /**
162
- * The collection whose entry this property sits inside — `connectors`, `pullers`, `objects`, … — as the
163
- * walker already tracks it. Optional so existing callers keep compiling; supplying it is what lets a
164
- * property mean one thing in a step argument and another on a component of its own collection (FR-47).
165
- */
166
- enclosingCollection) {
167
- const entry = BY_NAME.get(property);
168
- if (!entry)
169
- return undefined;
170
- if (entry.tokenFormOnly && !isTokenForm(value))
171
- return undefined;
172
- // Checked BEFORE the discriminator: position decides whether there is a reference at all, and only then
173
- // does anything ask what it points into.
174
- if (enclosingCollection !== undefined &&
175
- entry.opaqueInCollections?.includes(enclosingCollection)) {
176
- return undefined;
177
- }
178
- if (!entry.discriminator) {
179
- return {
180
- property,
181
- ...(entry.collection ? { collection: entry.collection } : {}),
182
- };
183
- }
184
- const { siblings: names, byValue, fallback } = entry.discriminator;
185
- for (const name of names) {
186
- const raw = siblings?.[name];
187
- if (raw === undefined || raw === null)
188
- continue;
189
- const key = String(raw);
190
- // `has` rather than `get`, because a MAPPED `undefined` ("`SELF` references nothing") and an
191
- // UNMAPPED value ("a type nobody has measured yet") are different answers that both come back
192
- // as `undefined` from `get`. Claiming a collection for an unknown type is how this registry
193
- // was wrong the first time.
194
- if (!byValue.has(key))
195
- return undefined;
196
- const collection = byValue.get(key);
197
- // Present, measured, and not a component reference — `entityType: SELF`, `PROFILE`.
198
- if (collection === undefined)
199
- return undefined;
200
- return { property, collection };
201
- }
202
- return { property, ...(fallback ? { collection: fallback } : {}) };
203
- }
204
- /** Fast membership test for the walk in `queries.ts`. */
205
- export const REFERENCE_PROPERTIES = REFERENCE_PROPERTY_LIST.map((r) => r.property);
206
- const BY_NAME = new Map(REFERENCE_PROPERTY_LIST.map((r) => [r.property, r]));
207
- export const referencePropertyFor = (property) => BY_NAME.get(property);
208
- /**
209
- * `*Id` properties MEASURED at 0% resolution — not references, recorded so their absence reads
210
- * as a decision rather than an oversight.
211
- *
212
- * They hold runtime UUIDs, environment tokens or payload field names. Without this list the next
213
- * reader sees `metricId` missing from the set above and adds it, and every metric configuration
214
- * in the corpus grows a dangling-reference diagnostic.
215
- *
216
- * Every entry here has a row in the table above. `templateId` and `reportId` were previously
217
- * listed and have been REMOVED: they never occurred in the sampled projects at all, so "resolved
218
- * 0%" was never true of them — no-occurrences is not the same measurement as never-resolves, and
219
- * a list whose stated basis is measurement must not carry entries that were only assumed. They
220
- * do appear elsewhere in the corpus (`reportId` ~91 authored occurrences), so they are left
221
- * deliberately unclassified until someone measures them.
222
- */
223
- export const NON_REFERENCE_ID_PROPERTIES = [
224
- 'metricId',
225
- 'providerId',
226
- 'columnIds',
227
- 'systemId',
228
- 'integrationAppId',
229
- 'credentialId',
230
- 'profileId',
231
- 'itemIds',
232
- ];
233
- /**
234
- * Blocks whose `id` names a component — the corpus's DOMINANT reference form.
235
- *
236
- * `objectAssociations` wires a Task to its entities like this:
237
- *
238
- * objectAssociations:
239
- * "**Orders_Task_Id**":
240
- * table: { id: "**Orders_Table_Id**" }
241
- * puller: { id: "**Orders_Puller_Id**", resultKey: rows }
242
- *
243
- * Counted across the corpus's AUTHORED partials (`output.yaml` and `__configs` excluded):
244
- *
245
- * nested `table:` 1,575 flat `tableId:` 308
246
- * nested `puller:` 1,695 flat `pullerId:` 38
247
- * nested `pusher:` 912 flat `pusherId:` 48
248
- * ----- ---
249
- * 4,182 394
250
- *
251
- * The nested form outnumbers the flat one by roughly 10:1 — it is how the corpus wires a Task to
252
- * its entities, and a registry built only on flat property names saw NONE of it. The flat form is
253
- * a real minority, not noise, so both are supported.
254
- *
255
- * (An earlier draft of this comment said "4 / 2 / 5" and "three orders of magnitude". Those were
256
- * the nine-project RESOLUTION sample from the table above, quoted under a corpus-wide heading —
257
- * a different measurement of a different population. Corrected 2026-08-02.)
258
- *
259
- * The block carries more than the id (`resultKey`, for one), so the reference is the block's
260
- * `id` specifically, reported as `table.id` rather than as `table`.
261
- */
262
- export const NESTED_REFERENCE_BLOCKS = [
263
- { property: 'table', collection: 'tables' },
264
- { property: 'puller', collection: 'pullers' },
265
- { property: 'pusher', collection: 'pushers' },
266
- ];
267
- const NESTED_BY_NAME = new Map(NESTED_REFERENCE_BLOCKS.map((r) => [r.property, r]));
268
- export const nestedReferenceBlockFor = (property) => NESTED_BY_NAME.get(property);
269
- /**
270
- * Collections whose component KEY is itself a reference into another collection.
271
- *
272
- * An `objectAssociations` entry is keyed BY the objectId it describes — that is what makes it
273
- * that object's association rather than a component that merely shares its name. Modelling it
274
- * matters twice: `getRelatedTask` can answer for an association, and renaming a Task has to
275
- * carry the association key with it, which only shows up in a blast radius if the key is an edge.
276
- */
277
- export const COLLECTIONS_KEYED_BY_REFERENCE = new Map([
278
- ['objectAssociations', 'objects'],
279
- /**
280
- * ADDED 2026-08-06, on a reported bug: a Task's transformations and validations were invisible.
281
- *
282
- * Both are keyed by the Task they belong to, exactly as an association is — the key IS the objectId, and
283
- * the value is that Task's list:
284
- *
285
- * transformations:
286
- * "**MisaAmisSapoWeb__Inventories_Task_Id**":
287
- * - id: "**…_GetProductVariant_Transformation_Id**"
288
- * type: SQL
289
- *
290
- * Without the key modelled as a reference there is no edge between the two, so nothing could answer
291
- * "which transformations does this Task have". Probed on `001-projects/catafa/sapo-misa`: the graph held
292
- * 2 transformation and 5 validation components, and the Task's incoming relations were the association
293
- * alone. The components were there; the edge was not.
294
- *
295
- * It matters twice, as the association's entry says: a query can answer for a Task, and renaming a Task
296
- * carries its transformations and validations with it — which only shows up in a blast radius if the key
297
- * is an edge.
298
- */
299
- ['transformations', 'objects'],
300
- ['validations', 'objects'],
301
- ]);
302
- /** The property name reported for a reference carried by a component's own key. */
303
- export const KEY_REFERENCE_PROPERTY = '(key)';
304
- /**
305
- * The connector a connection names — `connectorId` first, `providerId` second (FR-1, AD-24).
306
- *
307
- * The read order exists in four places: `BaseStepExecutor` (untyped), `ConnectorDefinition.ResolvedConnectorId`
308
- * (typed), `WebhookPartitioner` (via the accessor) and — found missing by the Epic 1 review — the CLI's task
309
- * tooling. FR-1 says *every* runtime path, and the CLI reading only the legacy spelling meant a
310
- * `connectorId`-only connection, exactly what FR-3's rename produces at scale, hard-stopped task generation
311
- * with *"Connector undefined not found"*.
312
- *
313
- * Blank counts as absent, matching the untyped path: `Guid.Empty` has no equivalent here, but an empty string
314
- * does, and a half-written `connectorId: ""` must not beat a real legacy value.
315
- */
316
- export function resolvedConnectorIdOf(connection) {
317
- const usable = (value) => {
318
- const text = typeof value === 'string'
319
- ? value
320
- : typeof value === 'number'
321
- ? String(value)
322
- : undefined;
323
- if (text === undefined || text.trim() === '')
324
- return undefined;
325
- // All-zeros counts as absent, matching `ConnectorIdentity.IsDeclared` in C#. The Epic 1 review found the
326
- // two sides disagreeing about exactly this literal.
327
- return text.trim() === '00000000-0000-0000-0000-000000000000'
328
- ? undefined
329
- : text;
330
- };
331
- return usable(connection?.connectorId) ?? usable(connection?.providerId);
332
- }
333
- /**
334
- * A connector identity that is written but cannot be used (FR-9, Story 2.1).
335
- *
336
- * "Well formed" means a GUID. Not a name, not a slug, not a URL — the platform's connector registry is keyed by
337
- * GUID, so anything else cannot resolve however plausible it looks.
338
- *
339
- * ⛔ ONE definition, deliberately. The same rule is expressed as a `pattern` in the shipped connection schema
340
- * and as `ConnectorIdentity` in C#, and Epic 1's review found what happens when a rule this small gets written
341
- * three times: the copies disagreed about an all-zeros GUID and nobody noticed, because the disagreeing input
342
- * was the one case no suite covered. The schema, the rule and the runtime must answer the same question the
343
- * same way.
344
- *
345
- * A compose-time TOKEN is not judged here. In composed output an unresolved `**Token**` means the VARIABLE
346
- * failed to resolve, which `VAR-1` already reports — and two findings for one cause is how a Problems panel
347
- * stops being read.
348
- */
349
- const GUID = /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/;
350
- /**
351
- * An identity that is STILL a token after composition — the variable failed, and `VAR-1` owns that.
352
- *
353
- * ⛔ A NAME for `isTokenForm`, not a second implementation. It shipped as a byte-identical copy of the regex
354
- * 350 lines above its original, in the file whose own docstring says *"ONE definition, deliberately … Epic 1's
355
- * review found what happens when a rule this small gets written three times."* Found by the Epic 2 review; kept
356
- * as an alias rather than deleted because the two names say different things at their call sites — one asks
357
- * "is this the shape a reference resolves in", the other "did substitution fail here".
358
- */
359
- export const isUnresolvedToken = isTokenForm;
360
- export function isWellFormedConnectorIdentity(value) {
361
- const trimmed = value.trim();
362
- if (!GUID.test(trimmed))
363
- return false;
364
- // All-zeros is what an undeclared identity deserialises to on the typed side. It parses as a GUID and names
365
- // no connector, so it is "absent" rather than "malformed" — `resolvedConnectorIdOf` already declines it.
366
- return trimmed !== '00000000-0000-0000-0000-000000000000';
367
- }
368
- //# sourceMappingURL=references.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"references.js","sourceRoot":"","sources":["../src/references.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;AAEH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAEH;;;;;GAKG;AACH,MAAM,UAAU,GAAG,iBAAiB,CAAC;AAErC,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,KAAa,EAAW,EAAE,CACpD,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;AAmDhC,yEAAyE;AACzE,MAAM,mBAAmB,GAAG,IAAI,GAAG,CAA6B;IAC9D,CAAC,MAAM,EAAE,SAAS,CAAC;IACnB,+EAA+E;IAC/E,CAAC,MAAM,EAAE,SAAS,CAAC;IACnB,kFAAkF;IAClF,CAAC,SAAS,EAAE,SAAS,CAAC;CACvB,CAAC,CAAC;AAEH,wEAAwE;AACxE,MAAM,mBAAmB,GAAG,IAAI,GAAG,CAA6B;IAC9D,CAAC,QAAQ,EAAE,SAAS,CAAC;IACrB,CAAC,QAAQ,EAAE,SAAS,CAAC;IACrB,CAAC,QAAQ,EAAE,SAAS,CAAC;IACrB,CAAC,WAAW,EAAE,cAAc,CAAC;CAC9B,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,uBAAuB,GAAiC;IACnE,EAAE,QAAQ,EAAE,QAAQ,EAAE,UAAU,EAAE,SAAS,EAAE;IAC7C,EAAE,QAAQ,EAAE,UAAU,EAAE,UAAU,EAAE,SAAS,EAAE;IAC/C,EAAE,QAAQ,EAAE,WAAW,EAAE,UAAU,EAAE,SAAS,EAAE;IAChD,EAAE,QAAQ,EAAE,WAAW,EAAE,UAAU,EAAE,SAAS,EAAE;IAChD,EAAE,QAAQ,EAAE,UAAU,EAAE,UAAU,EAAE,SAAS,EAAE;IAC/C,EAAE,QAAQ,EAAE,UAAU,EAAE,UAAU,EAAE,SAAS,EAAE;IAC/C,EAAE,QAAQ,EAAE,SAAS,EAAE,UAAU,EAAE,QAAQ,EAAE;IAC7C;;;;;;;;;;;;;OAaG;IACH,EAAE,QAAQ,EAAE,YAAY,EAAE,UAAU,EAAE,SAAS,EAAE;IACjD,6DAA6D;IAC7D,EAAE,QAAQ,EAAE,cAAc,EAAE,UAAU,EAAE,YAAY,EAAE;IACtD,EAAE,QAAQ,EAAE,kBAAkB,EAAE,UAAU,EAAE,YAAY,EAAE;IAC1D,kGAAkG;IAClG,6EAA6E;IAC7E;QACE,QAAQ,EAAE,aAAa;QACvB,UAAU,EAAE,YAAY;QACxB,mBAAmB,EAAE,CAAC,YAAY,CAAC;KACpC;IACD;QACE,QAAQ,EAAE,UAAU;QACpB,aAAa,EAAE,IAAI;QACnB,aAAa,EAAE;YACb,QAAQ,EAAE,CAAC,YAAY,CAAC;YACxB,OAAO,EAAE,mBAAmB;YAC5B,QAAQ,EAAE,SAAS;SACpB;KACF;IACD;QACE,QAAQ,EAAE,UAAU;QACpB,aAAa,EAAE,IAAI;QACnB,aAAa,EAAE;YACb,2FAA2F;YAC3F,kEAAkE;YAClE,QAAQ,EAAE,CAAC,YAAY,EAAE,YAAY,CAAC;YACtC,OAAO,EAAE,IAAI,GAAG,CAAC,CAAC,GAAG,mBAAmB,EAAE,GAAG,mBAAmB,CAAC,CAAC;YAClE,QAAQ,EAAE,SAAS;SACpB;KACF;CACF,CAAC;AAUF;;;;;;GAMG;AACH,MAAM,UAAU,oBAAoB,CAClC,QAAgB,EAChB,KAAa,EACb,QAAkC;AAClC;;;;GAIG;AACH,mBAA4B;IAE5B,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IACpC,IAAI,CAAC,KAAK;QAAE,OAAO,SAAS,CAAC;IAC7B,IAAI,KAAK,CAAC,aAAa,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC;QAAE,OAAO,SAAS,CAAC;IACjE,wGAAwG;IACxG,yCAAyC;IACzC,IACE,mBAAmB,KAAK,SAAS;QACjC,KAAK,CAAC,mBAAmB,EAAE,QAAQ,CAAC,mBAAmB,CAAC,EACxD,CAAC;QACD,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,IAAI,CAAC,KAAK,CAAC,aAAa,EAAE,CAAC;QACzB,OAAO;YACL,QAAQ;YACR,GAAG,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,KAAK,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SAC9D,CAAC;IACJ,CAAC;IAED,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,GAAG,KAAK,CAAC,aAAa,CAAC;IACnE,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,GAAG,GAAG,QAAQ,EAAE,CAAC,IAAI,CAAC,CAAC;QAC7B,IAAI,GAAG,KAAK,SAAS,IAAI,GAAG,KAAK,IAAI;YAAE,SAAS;QAChD,MAAM,GAAG,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;QACxB,6FAA6F;QAC7F,8FAA8F;QAC9F,4FAA4F;QAC5F,4BAA4B;QAC5B,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC;YAAE,OAAO,SAAS,CAAC;QACxC,MAAM,UAAU,GAAG,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACpC,oFAAoF;QACpF,IAAI,UAAU,KAAK,SAAS;YAAE,OAAO,SAAS,CAAC;QAC/C,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,CAAC;IAClC,CAAC;IACD,OAAO,EAAE,QAAQ,EAAE,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;AACrE,CAAC;AAED,yDAAyD;AACzD,MAAM,CAAC,MAAM,oBAAoB,GAC/B,uBAAuB,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC;AAEjD,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,uBAAuB,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;AAE7E,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAClC,QAAgB,EACe,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;AAE1D;;;;;;;;;;;;;;GAcG;AACH,MAAM,CAAC,MAAM,2BAA2B,GAAsB;IAC5D,UAAU;IACV,YAAY;IACZ,WAAW;IACX,UAAU;IACV,kBAAkB;IAClB,cAAc;IACd,WAAW;IACX,SAAS;CACV,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,MAAM,CAAC,MAAM,uBAAuB,GAAiC;IACnE,EAAE,QAAQ,EAAE,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE;IAC3C,EAAE,QAAQ,EAAE,QAAQ,EAAE,UAAU,EAAE,SAAS,EAAE;IAC7C,EAAE,QAAQ,EAAE,QAAQ,EAAE,UAAU,EAAE,SAAS,EAAE;CAC9C,CAAC;AAEF,MAAM,cAAc,GAAG,IAAI,GAAG,CAC5B,uBAAuB,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,CACpD,CAAC;AAEF,MAAM,CAAC,MAAM,uBAAuB,GAAG,CACrC,QAAgB,EACe,EAAE,CAAC,cAAc,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;AAEjE;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,8BAA8B,GACzC,IAAI,GAAG,CAAC;IACN,CAAC,oBAAoB,EAAE,SAAS,CAAC;IACjC;;;;;;;;;;;;;;;;;;;OAmBG;IACH,CAAC,iBAAiB,EAAE,SAAS,CAAC;IAC9B,CAAC,aAAa,EAAE,SAAS,CAAC;CAC3B,CAAC,CAAC;AAEL,mFAAmF;AACnF,MAAM,CAAC,MAAM,sBAAsB,GAAG,OAAO,CAAC;AAE9C;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,qBAAqB,CACnC,UACoE;IAEpE,MAAM,MAAM,GAAG,CAAC,KAAc,EAAE,EAAE;QAChC,MAAM,IAAI,GACR,OAAO,KAAK,KAAK,QAAQ;YACvB,CAAC,CAAC,KAAK;YACP,CAAC,CAAC,OAAO,KAAK,KAAK,QAAQ;gBACzB,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC;gBACf,CAAC,CAAC,SAAS,CAAC;QAClB,IAAI,IAAI,KAAK,SAAS,IAAI,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE;YAAE,OAAO,SAAS,CAAC;QAC/D,yGAAyG;QACzG,oDAAoD;QACpD,OAAO,IAAI,CAAC,IAAI,EAAE,KAAK,sCAAsC;YAC3D,CAAC,CAAC,SAAS;YACX,CAAC,CAAC,IAAI,CAAC;IACX,CAAC,CAAC;IACF,OAAO,MAAM,CAAC,UAAU,EAAE,WAAW,CAAC,IAAI,MAAM,CAAC,UAAU,EAAE,UAAU,CAAC,CAAC;AAC3E,CAAC;AAED;;;;;;;;;;;;;;;GAeG;AACH,MAAM,IAAI,GACR,+EAA+E,CAAC;AAElF;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,WAAW,CAAC;AAE7C,MAAM,UAAU,6BAA6B,CAAC,KAAa;IACzD,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC;IAC7B,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC;QAAE,OAAO,KAAK,CAAC;IACtC,4GAA4G;IAC5G,yGAAyG;IACzG,OAAO,OAAO,KAAK,sCAAsC,CAAC;AAC5D,CAAC"}
@@ -1,88 +0,0 @@
1
- /**
2
- * The two templating layers, told apart (FR-50, Phase 1 Story 3.8).
3
- *
4
- * A value can carry substitution that happens when you BUILD and substitution that happens when
5
- * it RUNS, and the difference decides who finds out about a mistake:
6
- *
7
- * `**VariableKey**` COMPOSE-TIME. The composer substitutes it from the project's variable
8
- * pool. A missing one is caught at compose, by the person composing.
9
- * `{{ … }}` RUNTIME. The worker evaluates it (Scriban) against live data. A missing
10
- * one is caught in production, by whoever is on call.
11
- *
12
- * Conflating them is how a `{{env.__HSS_X}}` gets reported as an unresolved compose-time
13
- * variable — noise on something that is working exactly as designed — and, worse, how a genuinely
14
- * missing environment key gets the same severity as a typo'd variable name.
15
- *
16
- * ALL `{{ … }}` IS SCRIBAN — including inside a JSONata expression. A JSONata value may embed
17
- * Scriban so the JSONata itself can be built dynamically, and the worker evaluates Scriban FIRST,
18
- * then treats the result as JSONata. So there is no nested-language boundary to reason about
19
- * here: a `{{ … }}` occurrence is runtime Scriban wherever it appears, and the surrounding
20
- * expression language does not change that.
21
- *
22
- * RUNTIME IS SCRIBAN, NOT JUST `env`. The corpus holds ~30,000 `{{ … }}` occurrences: control
23
- * flow (`{{end}}`), pipes (`{{ '' | uuid }}`), runtime data (`{{puller.before.X}}`) and 377
24
- * distinct `env.__HSS_*` keys. The AC names the `env` case because that is the one with an
25
- * external dependency, so it is classified separately rather than being the whole definition of
26
- * "runtime" — a narrower model would have mislabelled the other 29,000.
27
- */
28
- /** When the substitution happens, and therefore who discovers a mistake. */
29
- export type TemplatingLayer = 'compose-time' | 'runtime';
30
- /**
31
- * What a runtime expression reaches for.
32
- *
33
- * `environment` is singled out because it depends on something outside the template entirely —
34
- * a key that must exist in the deployment — so a later diagnostic can treat it differently from
35
- * an expression over data the worker already holds.
36
- */
37
- export type RuntimeReference = 'environment' | 'expression';
38
- export interface TemplateOccurrence {
39
- readonly layer: TemplatingLayer;
40
- /** Only meaningful for `runtime`. */
41
- readonly runtimeReference?: RuntimeReference;
42
- /** The full matched text, e.g. `**Foo**` or `{{ env.__HSS_X }}`. */
43
- readonly raw: string;
44
- /**
45
- * What the occurrence names: the variable key for compose-time, the environment key for a
46
- * runtime `env` reference, and the trimmed expression otherwise.
47
- */
48
- readonly key: string;
49
- /**
50
- * Every environment key this occurrence reads, for a `runtime` occurrence that reads any.
51
- *
52
- * `key` carries only the FIRST, because it is one string. `{{ env.A + env.B }}` is one expression
53
- * reading two keys, and the whole reason `environment` is a distinct `runtimeReference` is so a
54
- * later rule can ask "does this deployment define them" — which it cannot do for `env.B` if only
55
- * `env.A` was ever recorded.
56
- */
57
- readonly environmentKeys?: readonly string[];
58
- /**
59
- * Offsets into the VALUE as parsed, not into the source text.
60
- *
61
- * Named precisely because the difference bites: a caller receives `scalar.value`, which for a
62
- * quoted scalar has had escapes expanded and for a block scalar has been folded and dedented, so
63
- * these offsets are not source positions and cannot be turned into one without the scalar's own
64
- * range. An earlier comment promised "so a caller can map back to a source range", which is not
65
- * something these offsets alone can do.
66
- */
67
- readonly start: number;
68
- readonly end: number;
69
- }
70
- /**
71
- * Every templating occurrence in a value, each classified independently.
72
- *
73
- * Independently matters: one value can mix layers — a URL built from a compose-time variable
74
- * followed by a runtime expression is both — and a classifier returning a single verdict per
75
- * value would have to be wrong about one of them.
76
- */
77
- export declare function classifyTemplating(value: string): TemplateOccurrence[];
78
- /** Does this value carry any compose-time substitution? */
79
- export declare function hasComposeTimeTemplating(value: string): boolean;
80
- /**
81
- * Compose-time keys in a value — what a resolver needs.
82
- *
83
- * Runtime occurrences are deliberately absent: asking the variable pool about `{{ item.id }}`
84
- * would always fail, and reporting that failure would be reporting on something the composer
85
- * was never responsible for.
86
- */
87
- export declare function composeTimeKeys(value: string): string[];
88
- //# sourceMappingURL=templating.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"templating.d.ts","sourceRoot":"","sources":["../src/templating.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,4EAA4E;AAC5E,MAAM,MAAM,eAAe,GAAG,cAAc,GAAG,SAAS,CAAC;AAEzD;;;;;;GAMG;AACH,MAAM,MAAM,gBAAgB,GAAG,aAAa,GAAG,YAAY,CAAC;AAE5D,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,KAAK,EAAE,eAAe,CAAC;IAChC,qCAAqC;IACrC,QAAQ,CAAC,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;IAC7C,oEAAoE;IACpE,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB;;;OAGG;IACH,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB;;;;;;;OAOG;IACH,QAAQ,CAAC,eAAe,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC7C;;;;;;;;OAQG;IACH,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;CACtB;AAwBD;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,kBAAkB,EAAE,CAgCtE;AAED,2DAA2D;AAC3D,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAE/D;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAQvD"}
@@ -1,103 +0,0 @@
1
- /**
2
- * The two templating layers, told apart (FR-50, Phase 1 Story 3.8).
3
- *
4
- * A value can carry substitution that happens when you BUILD and substitution that happens when
5
- * it RUNS, and the difference decides who finds out about a mistake:
6
- *
7
- * `**VariableKey**` COMPOSE-TIME. The composer substitutes it from the project's variable
8
- * pool. A missing one is caught at compose, by the person composing.
9
- * `{{ … }}` RUNTIME. The worker evaluates it (Scriban) against live data. A missing
10
- * one is caught in production, by whoever is on call.
11
- *
12
- * Conflating them is how a `{{env.__HSS_X}}` gets reported as an unresolved compose-time
13
- * variable — noise on something that is working exactly as designed — and, worse, how a genuinely
14
- * missing environment key gets the same severity as a typo'd variable name.
15
- *
16
- * ALL `{{ … }}` IS SCRIBAN — including inside a JSONata expression. A JSONata value may embed
17
- * Scriban so the JSONata itself can be built dynamically, and the worker evaluates Scriban FIRST,
18
- * then treats the result as JSONata. So there is no nested-language boundary to reason about
19
- * here: a `{{ … }}` occurrence is runtime Scriban wherever it appears, and the surrounding
20
- * expression language does not change that.
21
- *
22
- * RUNTIME IS SCRIBAN, NOT JUST `env`. The corpus holds ~30,000 `{{ … }}` occurrences: control
23
- * flow (`{{end}}`), pipes (`{{ '' | uuid }}`), runtime data (`{{puller.before.X}}`) and 377
24
- * distinct `env.__HSS_*` keys. The AC names the `env` case because that is the one with an
25
- * external dependency, so it is classified separately rather than being the whole definition of
26
- * "runtime" — a narrower model would have mislabelled the other 29,000.
27
- */
28
- /**
29
- * Identifier-shaped, matching the composer's own residual-token rule.
30
- *
31
- * Deliberately not `\*\*.+\*\*`: markdown bold is indistinguishable from a variable token by
32
- * shape alone, and a looser pattern would classify every bold phrase in a `description` as an
33
- * unresolved variable. The composer already draws the line here; drawing it differently would
34
- * mean two answers to one question.
35
- */
36
- const COMPOSE_TIME_RE = /\*\*[A-Za-z0-9_]+\*\*/g;
37
- /** Scriban, non-greedy so adjacent expressions do not merge into one. */
38
- const RUNTIME_RE = /\{\{[\s\S]*?\}\}/g;
39
- /**
40
- * A runtime expression that reads an environment key. GLOBAL — an expression can read several.
41
- *
42
- * The leading guard excludes `myenv.X`, but a QUOTE satisfies `[^A-Za-z0-9_.]` too, so
43
- * `{{ "env.LITERAL" }}` was reported as a deployment dependency on a key that is a string literal.
44
- * Quotes are now excluded explicitly.
45
- */
46
- const ENV_REF_RE = /(?:^|[^A-Za-z0-9_.'"`])env\.([A-Za-z0-9_]+)/g;
47
- /**
48
- * Every templating occurrence in a value, each classified independently.
49
- *
50
- * Independently matters: one value can mix layers — a URL built from a compose-time variable
51
- * followed by a runtime expression is both — and a classifier returning a single verdict per
52
- * value would have to be wrong about one of them.
53
- */
54
- export function classifyTemplating(value) {
55
- if (typeof value !== 'string' || value.length === 0)
56
- return [];
57
- const found = [];
58
- for (const m of value.matchAll(COMPOSE_TIME_RE)) {
59
- found.push({
60
- layer: 'compose-time',
61
- raw: m[0],
62
- key: m[0].slice(2, -2),
63
- start: m.index,
64
- end: m.index + m[0].length,
65
- });
66
- }
67
- for (const m of value.matchAll(RUNTIME_RE)) {
68
- const inner = m[0].slice(2, -2).trim();
69
- // ALL of them. `ENV_REF_RE` was non-global and used with a single `.exec`, so a compound
70
- // expression reported only its first key and every later one was invisible.
71
- const envKeys = [...inner.matchAll(ENV_REF_RE)].map((e) => e[1]);
72
- found.push({
73
- layer: 'runtime',
74
- runtimeReference: envKeys.length > 0 ? 'environment' : 'expression',
75
- raw: m[0],
76
- key: envKeys.length > 0 ? envKeys[0] : inner,
77
- ...(envKeys.length > 0 ? { environmentKeys: envKeys } : {}),
78
- start: m.index,
79
- end: m.index + m[0].length,
80
- });
81
- }
82
- // Source order, so a caller reporting occurrences reads them the way the author wrote them.
83
- return found.sort((a, b) => a.start - b.start);
84
- }
85
- /** Does this value carry any compose-time substitution? */
86
- export function hasComposeTimeTemplating(value) {
87
- return classifyTemplating(value).some((t) => t.layer === 'compose-time');
88
- }
89
- /**
90
- * Compose-time keys in a value — what a resolver needs.
91
- *
92
- * Runtime occurrences are deliberately absent: asking the variable pool about `{{ item.id }}`
93
- * would always fail, and reporting that failure would be reporting on something the composer
94
- * was never responsible for.
95
- */
96
- export function composeTimeKeys(value) {
97
- return [
98
- ...new Set(classifyTemplating(value)
99
- .filter((t) => t.layer === 'compose-time')
100
- .map((t) => t.key)),
101
- ];
102
- }
103
- //# sourceMappingURL=templating.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"templating.js","sourceRoot":"","sources":["../src/templating.ts"],"names":[],"mappings":"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"}
package/dist/uriPath.d.ts DELETED
@@ -1,43 +0,0 @@
1
- /**
2
- * URI path algebra — the AD-18 corollary.
3
- *
4
- * Core may not use `node:path` (AD-3, amended 2026-08-01): the VS Code web
5
- * extension host does not provide it, and a bundler polyfill is exactly how
6
- * desktop and web end up disagreeing about file identity. So core does its own
7
- * path arithmetic over **normalized URI strings**: POSIX `/` only, with `.` and
8
- * `..` collapsed explicitly.
9
- *
10
- * Pure string work. No IO, no Node builtins, no platform behaviour.
11
- */
12
- export declare function normalizeUri(uri: string): string;
13
- export declare function joinUri(base: string, ...segments: readonly string[]): string;
14
- export declare function dirnameUri(uri: string): string;
15
- export declare function basenameUri(uri: string): string;
16
- /**
17
- * True when `target` is absolute in its own right — rooted, drive-rooted, or schemed.
18
- *
19
- * Exported because `node:path`'s `isAbsolute` cannot answer this question for the web host: it
20
- * knows nothing of `vscode-vfs://`, and on Windows it would reject a rooted POSIX path that is
21
- * perfectly absolute in URI terms. This was the last of Story 1.5's 37 `path.*` call sites, and
22
- * it had to move before `resolveMdIncludes` could follow the rest of the compose logic into core.
23
- *
24
- * ### The drive letter (reported 2026-08-08)
25
- *
26
- * It answered FALSE for `C:\docs\notes.md`, which is as absolute as a path gets. `merge.ts` asks
27
- * this question at both `!md[…]` resolution sites — `isAbsoluteUri(ref) ? ref : resolveUri(base,
28
- * ref)` — so an author on Windows writing an absolute include had it joined onto the project's base
29
- * directory instead, producing `D:/project/C:/docs/notes.md` and an `ENOENT` naming a path nobody
30
- * wrote. On Linux the same include starts with `/` and was always answered correctly, which is why
31
- * only a Windows test run found it.
32
- */
33
- export declare function isAbsoluteUri(target: string): boolean;
34
- export declare function resolveUri(base: string, target: string): string;
35
- export declare function relativeUri(from: string, to: string): string;
36
- /**
37
- * The escape guard (AC 5). True only when `child` is strictly inside `parent`.
38
- *
39
- * Segment-aware on purpose: a `startsWith` check would accept `rootsibling/x`
40
- * for parent `root` and happily write outside the install target.
41
- */
42
- export declare function isInsideUri(parent: string, child: string): boolean;
43
- //# sourceMappingURL=uriPath.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"uriPath.d.ts","sourceRoot":"","sources":["../src/uriPath.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAkDH,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAWhD;AAED,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,QAAQ,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,CAM5E;AAED,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAM9C;AAED,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAK/C;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAOrD;AAED,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAE/D;AAED,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,MAAM,CAa5D;AAED;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAUlE"}