@unified-product-graph/core 0.7.1 → 0.7.3
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 +58 -0
- package/README.md +1 -1
- package/dist/index.cjs +919 -900
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +503 -441
- package/dist/index.d.ts +503 -441
- package/dist/index.js +919 -900
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/spec/UPG-MARKDOWN-v0.1.md +45 -45
- package/spec/examples/cms-field-guide.upg +7 -7
- package/spec/examples/enterprise-pilot-results.upg.md +9 -9
- package/spec/examples/enterprise-pilot.upg +6 -6
- package/spec/examples/feature-decision.upg.md +4 -4
- package/spec/examples/metric-tracking.upg.md +5 -5
- package/spec/examples/persona-minimal.upg.md +2 -2
package/package.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
# UPG Markdown
|
|
1
|
+
# UPG Markdown: Format Specification (v0.1)
|
|
2
2
|
|
|
3
3
|
> The literate variant of the `.upg` JSON format.
|
|
4
4
|
> Human-authored Markdown with typed entity references that resolve against a product graph.
|
|
5
5
|
|
|
6
6
|
**Format version:** 0.1
|
|
7
|
-
**Status:** Pragmatic spec (not formal grammar
|
|
7
|
+
**Status:** Pragmatic spec (not formal grammar; written the way good web specs are written).
|
|
8
8
|
**Reference implementation:** `@unified-product-graph/markdown` on npm.
|
|
9
9
|
**Third-party parser conformance:** §3 below is the normative checklist for conformant parsers.
|
|
10
10
|
**License:** MIT.
|
|
@@ -16,16 +16,16 @@
|
|
|
16
16
|
A `.upg.md` file is a single CommonMark Markdown document with two additions:
|
|
17
17
|
|
|
18
18
|
1. **YAML frontmatter** declaring the document's identity and graph-membership.
|
|
19
|
-
2. **Inline typed references** in the body
|
|
19
|
+
2. **Inline typed references** in the body (`[[type:id]]` chips for entities, `{{type:id → type:id|verb}}` connectors for edges) and an optional fenced JSON escape hatch (` ```upg `) for declarations a renderer needs to resolve up-front.
|
|
20
20
|
|
|
21
21
|
It is **the same product graph as `.upg`**, expressed prose-first. A `.upg.md` document is itself an entity of type `document`; the references it contains are the graph the document narrates.
|
|
22
22
|
|
|
23
23
|
The format is designed for:
|
|
24
24
|
|
|
25
|
-
- **Human authoring
|
|
26
|
-
- **Round-trip with `.upg` JSON
|
|
27
|
-
- **Portability
|
|
28
|
-
- **Diffability
|
|
25
|
+
- **Human authoring**: write Markdown the way you already do; entities and edges sit inline.
|
|
26
|
+
- **Round-trip with `.upg` JSON**: a `.upg.md` and an equivalent `.upg` file describe the same graph.
|
|
27
|
+
- **Portability**: any Markdown-aware tool can render the document; UPG-aware tools resolve the chips.
|
|
28
|
+
- **Diffability**: line-oriented source, friendly to git, code review, and pair authoring.
|
|
29
29
|
|
|
30
30
|
Non-goals: HTML rendering semantics, live link resolution, embedding/search, MDX-style component syntax, multi-document workspace indexing. All are out of scope here. They MAY ship in tooling layers; they are not part of the format.
|
|
31
31
|
|
|
@@ -35,8 +35,8 @@ Non-goals: HTML rendering semantics, live link resolution, embedding/search, MDX
|
|
|
35
35
|
|
|
36
36
|
A `.upg.md` document has exactly two parts in this order:
|
|
37
37
|
|
|
38
|
-
1. **Frontmatter
|
|
39
|
-
2. **Body
|
|
38
|
+
1. **Frontmatter**: a YAML block delimited by `---` on its own lines (§3).
|
|
39
|
+
2. **Body**: CommonMark Markdown with inline references (§4–§6) and optional fenced `upg` blocks (§7).
|
|
40
40
|
|
|
41
41
|
```
|
|
42
42
|
---
|
|
@@ -60,7 +60,7 @@ The persona [[persona:alex-senior-pm]] pursues
|
|
|
60
60
|
|
|
61
61
|
## 3. Frontmatter
|
|
62
62
|
|
|
63
|
-
The frontmatter MUST be the first construct in the file. If the opening `---` is absent, the document is not a `.upg.md
|
|
63
|
+
The frontmatter MUST be the first construct in the file. If the opening `---` is absent, the document is not a `.upg.md`. UPG-aware tools SHOULD treat it as plain Markdown and emit a `MISSING_FRONTMATTER` error if UPG semantics are required.
|
|
64
64
|
|
|
65
65
|
### 3.1 Required fields
|
|
66
66
|
|
|
@@ -72,7 +72,7 @@ The frontmatter MUST be the first construct in the file. If the opening `---` is
|
|
|
72
72
|
| `entity_type` | string literal `document` | The document is an entity. v0.1 fixes this to `document`. |
|
|
73
73
|
| `entity_id` | string | Stable ID of the document entity itself. MUST match `^[a-z][a-z0-9_-]*$`. |
|
|
74
74
|
|
|
75
|
-
A document missing any required field is **invalid
|
|
75
|
+
A document missing any required field is **invalid**: a conforming parser emits `MISSING_REQUIRED_FIELD` and halts structural extraction. Chips and edges MAY still be reported as warnings for diagnostics.
|
|
76
76
|
|
|
77
77
|
### 3.2 Optional fields
|
|
78
78
|
|
|
@@ -101,11 +101,11 @@ This is the forward-compatibility commitment: tools that ship today MUST round-t
|
|
|
101
101
|
|
|
102
102
|
## 4. Body conventions
|
|
103
103
|
|
|
104
|
-
The body is **prose-first**: standard CommonMark plus GitHub-Flavored Markdown (tables, fenced code blocks, strikethrough, task lists). The two Markdown extensions UPG MD adds
|
|
104
|
+
The body is **prose-first**: standard CommonMark plus GitHub-Flavored Markdown (tables, fenced code blocks, strikethrough, task lists). The two Markdown extensions UPG MD adds (typed chips and edge connectors) are **inline syntax inside ordinary prose**, not block-level constructs.
|
|
105
105
|
|
|
106
106
|
> **Rationale for prose-first.** See `08-decisions/2026-04-25-upg-md-prose-first.md`. Earlier drafts treated entity declarations as block constructs (Markdown headings + property tables). Authoring practice converged on inline references. The fenced `upg` block (§7) remains the structural escape hatch when prose alone cannot express what's needed.
|
|
107
107
|
|
|
108
|
-
A document MAY contain zero references. A `.upg.md` with no chips is a valid document
|
|
108
|
+
A document MAY contain zero references. A `.upg.md` with no chips is a valid document, narrating without graph-augmentation.
|
|
109
109
|
|
|
110
110
|
### 4.1 What Markdown extensions are in scope
|
|
111
111
|
|
|
@@ -134,11 +134,11 @@ Form: `[[type:id]]`, with optional creation marker, product scope, and pipe-deli
|
|
|
134
134
|
|
|
135
135
|
Capture groups:
|
|
136
136
|
|
|
137
|
-
1. **Creation flag
|
|
138
|
-
2. **Type
|
|
139
|
-
3. **ID
|
|
140
|
-
4. **Product slug
|
|
141
|
-
5. **Modifiers
|
|
137
|
+
1. **Creation flag**: `+` if present (§5.3), empty otherwise.
|
|
138
|
+
2. **Type**: `^[a-z][a-z_]*$`. Must match an entry in `UPG_ENTITY_META` to be **resolved**; unknown types remain valid syntax (§8.5).
|
|
139
|
+
3. **ID**: `^[a-z][a-z0-9_-]*$`. May be the entity's canonical UUID, slug, or any value in its `aliases[]` (§5.5).
|
|
140
|
+
4. **Product slug**: optional `@product` suffix (§5.4). Absent means inherit `upg_product` from frontmatter.
|
|
141
|
+
5. **Modifiers**: pipe-delimited segments parsed left-to-right (§5.6).
|
|
142
142
|
|
|
143
143
|
### 5.2 The basic forms
|
|
144
144
|
|
|
@@ -149,7 +149,7 @@ Capture groups:
|
|
|
149
149
|
| `[[type:id@product]]` | Cross-product reference (§5.4). |
|
|
150
150
|
| `[[type:id\|"label"]]` | Display label override (§5.6.1). |
|
|
151
151
|
| `[[type:id\|key:value]]` | Inline property assignment (§5.6.2). |
|
|
152
|
-
| `[[type:id\|key:value\|"label"]]` | Combined
|
|
152
|
+
| `[[type:id\|key:value\|"label"]]` | Combined: modifiers and display text in any order. |
|
|
153
153
|
|
|
154
154
|
### 5.3 Creation references
|
|
155
155
|
|
|
@@ -190,7 +190,7 @@ Inline properties are **assignments scoped to this reference**. Their interpreta
|
|
|
190
190
|
- **Loaders** treat the first such assignment for a given `(entity, property)` pair as authoritative; subsequent occurrences are SHOULD-warn (`DUPLICATE_INLINE_PROPERTY`).
|
|
191
191
|
- **Round-trippers** preserve every modifier byte-for-byte.
|
|
192
192
|
|
|
193
|
-
Conforming parsers MUST surface modifiers as an **ordered list** of `{kind: 'label', value}` or `{kind: 'property', key, value}` entries
|
|
193
|
+
Conforming parsers MUST surface modifiers as an **ordered list** of `{kind: 'label', value}` or `{kind: 'property', key, value}` entries; order is normative for round-trip (§8).
|
|
194
194
|
|
|
195
195
|
### 5.7 What chips do NOT do
|
|
196
196
|
|
|
@@ -210,7 +210,7 @@ Form: `{{src_type:src_id → tgt_type:tgt_id|verb}}`.
|
|
|
210
210
|
|
|
211
211
|
### 6.2 Endpoints
|
|
212
212
|
|
|
213
|
-
Both endpoints follow chip rules: type matches `^[a-z][a-z_]*$`, id matches `^[a-z][a-z0-9_-]*$`, optional `@product` suffix per §5.4. Endpoints inside an edge reference are **references**, not declarations
|
|
213
|
+
Both endpoints follow chip rules: type matches `^[a-z][a-z_]*$`, id matches `^[a-z][a-z0-9_-]*$`, optional `@product` suffix per §5.4. Endpoints inside an edge reference are **references**, not declarations. To declare an entity inside an edge, use a creation chip elsewhere in the document.
|
|
214
214
|
|
|
215
215
|
### 6.3 The arrow
|
|
216
216
|
|
|
@@ -218,9 +218,9 @@ The arrow MUST be either `→` (U+2192) or the ASCII fallback `->`. Conforming p
|
|
|
218
218
|
|
|
219
219
|
### 6.4 Verbs
|
|
220
220
|
|
|
221
|
-
The verb segment matches `[\w_]+` (lowercase identifiers with underscores). To be **resolved**, the verb MUST be a key in `UPG_EDGE_CATALOG`. Unknown verbs are warnings (§8.5), not errors
|
|
221
|
+
The verb segment matches `[\w_]+` (lowercase identifiers with underscores). To be **resolved**, the verb MUST be a key in `UPG_EDGE_CATALOG`. Unknown verbs are warnings (§8.5), not errors; the format is forward-compatible with edge types added in later spec versions.
|
|
222
222
|
|
|
223
|
-
A verb is **canonical** when paired with the correct `(src_type, tgt_type)
|
|
223
|
+
A verb is **canonical** when paired with the correct `(src_type, tgt_type)`: the spec catalogue keys edges by full triple. A verb that exists in the catalogue but is paired with the wrong endpoint types is `UNKNOWN_VERB_FOR_PAIR` (warning).
|
|
224
224
|
|
|
225
225
|
### 6.5 Inline edges and fenced edges are equivalent
|
|
226
226
|
|
|
@@ -230,7 +230,7 @@ An inline `{{a → b|verb}}` and a fenced declaration `{ "src": "a", "tgt": "b",
|
|
|
230
230
|
|
|
231
231
|
## 7. Fenced `upg` blocks (the JSON escape hatch)
|
|
232
232
|
|
|
233
|
-
Inline chips (§5) and inline edges (§6) are the primary authoring surface. **Fenced `upg` blocks remain part of v0.1 and MUST be supported by every conforming parser
|
|
233
|
+
Inline chips (§5) and inline edges (§6) are the primary authoring surface. **Fenced `upg` blocks remain part of v0.1 and MUST be supported by every conforming parser**; exporters, structural import, and round-trip with `.upg` JSON depend on them.
|
|
234
234
|
|
|
235
235
|
### 7.1 Block shape
|
|
236
236
|
|
|
@@ -259,14 +259,14 @@ Each entry in `edges[]` is equivalent to an inline `{{src → tgt|verb}}`. Requi
|
|
|
259
259
|
|
|
260
260
|
### 7.4 Malformed JSON
|
|
261
261
|
|
|
262
|
-
A malformed block is a **warning** (`INVALID_FENCED_JSON`) that affects only that block
|
|
262
|
+
A malformed block is a **warning** (`INVALID_FENCED_JSON`) that affects only that block; the rest of the document MUST still parse. Conforming parsers SHOULD continue to extract inline chips and edges around the malformed block.
|
|
263
263
|
|
|
264
264
|
### 7.5 When to use a fenced block
|
|
265
265
|
|
|
266
266
|
Use the fenced block when:
|
|
267
267
|
|
|
268
268
|
- A renderer needs property assignments that don't fit cleanly inline (e.g. a 12-field `metric_quality_assessment`).
|
|
269
|
-
- The same set of declarations is reused across multiple sections
|
|
269
|
+
- The same set of declarations is reused across multiple sections: declare once, reference inline thereafter.
|
|
270
270
|
- The document is generated by tooling that emits structural data and prose separately.
|
|
271
271
|
|
|
272
272
|
For most human authoring, inline chips suffice. Fenced blocks are the escape hatch, not the default.
|
|
@@ -280,14 +280,14 @@ For most human authoring, inline chips suffice. Fenced blocks are the escape hat
|
|
|
280
280
|
1. **Parse frontmatter first.** A document with malformed frontmatter is invalid; halt structural extraction (§3).
|
|
281
281
|
2. **Mask code regions.** Chips and edges inside fenced code blocks (` ``` ... ``` ` excluding `upg` blocks) and inline code spans (`` ` ... ` `` and `` `` ... `` ``) MUST NOT be extracted as references.
|
|
282
282
|
3. **Honour escapes.** `\[\[`, `\]\]`, `\{\{`, `\}\}` render literal brackets and MUST NOT be extracted (§8.3).
|
|
283
|
-
4. **Surface byte ranges.** For every chip and edge, expose the source byte range. Byte ranges are normative
|
|
283
|
+
4. **Surface byte ranges.** For every chip and edge, expose the source byte range. Byte ranges are normative; they enable round-trip edits (§9).
|
|
284
284
|
5. **Preserve unknown frontmatter keys.** Verbatim, including order (§3.3).
|
|
285
285
|
6. **Preserve modifier order.** Modifier segments inside a chip MUST round-trip in source order (§5.6).
|
|
286
286
|
|
|
287
287
|
### 8.2 Recommended behaviour (SHOULD)
|
|
288
288
|
|
|
289
289
|
1. **Normalise the arrow** to `→` on emit, preserving the source style on round-trip (§6.3).
|
|
290
|
-
2. **Warn, don't drop.** Unknown types, unknown verbs, unknown frontmatter keys, malformed individual chips
|
|
290
|
+
2. **Warn, don't drop.** Unknown types, unknown verbs, unknown frontmatter keys, malformed individual chips: warn and continue (§8.5).
|
|
291
291
|
3. **Layered ID resolution** per §5.5 if the parser also resolves.
|
|
292
292
|
4. **Multiline limit.** A single reference SHOULD NOT span more than 3 lines; longer spans warn (`MULTILINE_EXCEEDS_LIMIT`) and are not extracted.
|
|
293
293
|
|
|
@@ -334,7 +334,7 @@ A conforming parser **never silently drops structural content**.
|
|
|
334
334
|
|
|
335
335
|
### 8.6 Forward compatibility
|
|
336
336
|
|
|
337
|
-
An older conforming parser reading a newer document MUST round-trip without data loss for any construct it does not understand. This is non-negotiable. A future spec version MAY add new sigils, new modifier kinds, new fenced block types
|
|
337
|
+
An older conforming parser reading a newer document MUST round-trip without data loss for any construct it does not understand. This is non-negotiable. A future spec version MAY add new sigils, new modifier kinds, new fenced block types; older parsers preserve them as opaque text and warn.
|
|
338
338
|
|
|
339
339
|
---
|
|
340
340
|
|
|
@@ -345,8 +345,8 @@ An older conforming parser reading a newer document MUST round-trip without data
|
|
|
345
345
|
### 9.1 `.upg.md → .upg` (lossy)
|
|
346
346
|
|
|
347
347
|
Drops:
|
|
348
|
-
- Prose surrounding the chips (the document is preserved as a `document` entity with its body in `properties.body_md`, but Markdown structure
|
|
349
|
-
- Modifier display labels (`"Alex (CEO)"`)
|
|
348
|
+
- Prose surrounding the chips (the document is preserved as a `document` entity with its body in `properties.body_md`, but Markdown structure, including headings, paragraph layout, and formatting, is intentionally not modelled in the graph).
|
|
349
|
+
- Modifier display labels (`"Alex (CEO)"`): presentation, not graph data.
|
|
350
350
|
- Comments and incidental whitespace (§8.4).
|
|
351
351
|
|
|
352
352
|
Preserves:
|
|
@@ -360,7 +360,7 @@ Preserves:
|
|
|
360
360
|
|
|
361
361
|
Drops:
|
|
362
362
|
- Edge metadata that has no inline syntax (e.g. edge weights, custom edge properties beyond verb).
|
|
363
|
-
- Per-entity properties that aren't surfaceable as inline modifiers (large bodies of structured data
|
|
363
|
+
- Per-entity properties that aren't surfaceable as inline modifiers (large bodies of structured data stay in the graph; the document references them).
|
|
364
364
|
|
|
365
365
|
Preserves:
|
|
366
366
|
- Every entity → creation chip or fenced declaration.
|
|
@@ -381,20 +381,20 @@ Each example below is a complete `.upg.md` document. Each is validated by the ro
|
|
|
381
381
|
|
|
382
382
|
See `packages/upg-spec/spec/examples/`:
|
|
383
383
|
|
|
384
|
-
- `enterprise-pilot-results.upg.md
|
|
385
|
-
- `persona-minimal.upg.md
|
|
386
|
-
- `feature-decision.upg.md
|
|
387
|
-
- `metric-tracking.upg.md
|
|
384
|
+
- `enterprise-pilot-results.upg.md`: full experiment-report shape (existing reference document).
|
|
385
|
+
- `persona-minimal.upg.md`: minimal viable doc; frontmatter + a single chip (§10.1).
|
|
386
|
+
- `feature-decision.upg.md`: feature decision doc with chips + edges + a fenced `upg` block (§10.2).
|
|
387
|
+
- `metric-tracking.upg.md`: metric doc using property modifiers and cross-product references (§10.3).
|
|
388
388
|
|
|
389
|
-
### 10.1 `persona-minimal.upg.md
|
|
389
|
+
### 10.1 `persona-minimal.upg.md`: minimum viable document
|
|
390
390
|
|
|
391
391
|
The smallest valid `.upg.md`. Demonstrates required frontmatter and a single inline chip.
|
|
392
392
|
|
|
393
|
-
### 10.2 `feature-decision.upg.md
|
|
393
|
+
### 10.2 `feature-decision.upg.md`: chips + edges + fenced block
|
|
394
394
|
|
|
395
395
|
Demonstrates the full prose-first authoring shape: typed chips for the persona/feature/decision; an edge expressing the rationale relationship; a fenced `upg` block for the structural decision-record properties (the prose alone wouldn't fit them cleanly).
|
|
396
396
|
|
|
397
|
-
### 10.3 `metric-tracking.upg.md
|
|
397
|
+
### 10.3 `metric-tracking.upg.md`: modifiers + cross-product
|
|
398
398
|
|
|
399
399
|
Demonstrates inline property modifiers on metrics (`current:22%|target:30%`), the creation-marker form for newly-discovered entities, and a cross-product reference to a sibling product graph.
|
|
400
400
|
|
|
@@ -402,14 +402,14 @@ Demonstrates inline property modifiers on metrics (`current:22%|target:30%`), th
|
|
|
402
402
|
|
|
403
403
|
## 11. Versioning
|
|
404
404
|
|
|
405
|
-
The format spec is versioned independently from `@unified-product-graph/core`'s spec version (entity catalogue, edge catalogue, lifecycles)
|
|
405
|
+
The format spec is versioned independently from `@unified-product-graph/core`'s spec version (entity catalogue, edge catalogue, lifecycles), which evolve more frequently while the format remains stable across them.
|
|
406
406
|
|
|
407
407
|
- **Format version (this document):** `0.1`. Exposed at runtime as `MARKDOWN_FORMAT_VERSION` from `@unified-product-graph/core`.
|
|
408
408
|
- **Spec version (`upg_version` frontmatter):** the entity/edge catalogue version the document targets (e.g. `0.2`). Independent of format version.
|
|
409
409
|
|
|
410
410
|
A document declaring `upg_version: "0.2"` and consumed by a tool that bundles `@unified-product-graph/core@0.2.x` is in-spec. Forward compatibility (§8.6) handles version drift.
|
|
411
411
|
|
|
412
|
-
A future format `v0.2` would ship as `UPG-MARKDOWN-v0.2.md` alongside this document. The format is intentionally conservative about breaking changes
|
|
412
|
+
A future format `v0.2` would ship as `UPG-MARKDOWN-v0.2.md` alongside this document. The format is intentionally conservative about breaking changes; most evolution happens in catalogue versions, not format versions.
|
|
413
413
|
|
|
414
414
|
---
|
|
415
415
|
|
|
@@ -419,10 +419,10 @@ Explicitly **not** part of this spec:
|
|
|
419
419
|
|
|
420
420
|
- HTML rendering semantics, hover cards, syntax highlighting (consumer concerns).
|
|
421
421
|
- Live link resolution against a graph store (resolver tooling).
|
|
422
|
-
- Embedding semantics
|
|
422
|
+
- Embedding semantics (search, similarity, vector indexing).
|
|
423
423
|
- Workspace-level multi-document indexing and cross-document linking semantics.
|
|
424
|
-
- Speculative future syntax
|
|
425
|
-
- MDX / JSX components
|
|
424
|
+
- Speculative future syntax (templated chips, computed properties, inline queries, conditional rendering).
|
|
425
|
+
- MDX / JSX components: out of scope per §4.1; prose-first means CommonMark prose.
|
|
426
426
|
- Block-level entity declaration syntax (e.g. heading-keyed entity blocks). The format converged prose-first; block-level structure is the fenced `upg` block (§7).
|
|
427
427
|
|
|
428
428
|
Each of the above MAY be specified in a later format version or in tooling layers above the format. None affect parser conformance for v0.1.
|
|
@@ -431,7 +431,7 @@ Each of the above MAY be specified in a later format version or in tooling layer
|
|
|
431
431
|
|
|
432
432
|
## 13. Cross-references
|
|
433
433
|
|
|
434
|
-
- **Reference implementation:** `@unified-product-graph/markdown` on npm
|
|
434
|
+
- **Reference implementation:** `@unified-product-graph/markdown` on npm, providing `parse()`, `validate()`, `buildIndex()`, `toPlainMarkdown()`, `updateRefs()`, and TipTap converters.
|
|
435
435
|
- **Prose-first rationale:** UPG MD is authored for humans first; entity references are CommonMark-compatible inline chips so files render cleanly in any Markdown viewer.
|
|
436
436
|
- **`.upg` JSON format:** UPG MD is the literate variant of the `.upg` JSON format. See the UPG core spec for the JSON schema.
|
|
437
437
|
- **Site `/format` page:** [unifiedproductgraph.org/format](https://unifiedproductgraph.org/format) links to this document at a stable URL.
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
},
|
|
9
9
|
"product": {
|
|
10
10
|
"id": "cms-field-guide",
|
|
11
|
-
"title": "CMS Editor Paradigms
|
|
11
|
+
"title": "CMS Editor Paradigms: A Studio PM Field Guide",
|
|
12
12
|
"description": "Proof-of-spec fixture for the classification model. Models the CMS Field Editor Guide end-to-end using only canonical UPG entities: a single competitive_analysis dimensioned by two classification_axis children, with five classification_value children per axis, two exemplar competitor nodes classified against axis values, three empty_cells covering all rationale_kind values, and a persona with an anti_fit_for edge.",
|
|
13
13
|
"stage": "mvp"
|
|
14
14
|
},
|
|
@@ -26,13 +26,13 @@
|
|
|
26
26
|
"axis_a_value_ref": "val-composable",
|
|
27
27
|
"axis_b_value_ref": "val-wysiwyg",
|
|
28
28
|
"rationale_kind": "structural",
|
|
29
|
-
"rationale_md": "Composable rejects HTML blobs; WYSIWYG requires them. The two paradigms are structurally incompatible
|
|
29
|
+
"rationale_md": "Composable rejects HTML blobs; WYSIWYG requires them. The two paradigms are structurally incompatible: you can't simultaneously commit to a typed content graph and to a free-form HTML editor."
|
|
30
30
|
},
|
|
31
31
|
{
|
|
32
32
|
"axis_a_value_ref": "val-git-based",
|
|
33
33
|
"axis_b_value_ref": "val-portable-text",
|
|
34
34
|
"rationale_kind": "opportunity",
|
|
35
|
-
"rationale_md": "No technical reason
|
|
35
|
+
"rationale_md": "No technical reason, only adoption inertia. Watching brief: anyone shipping a starter that drops .md into Portable Text JSON could change the row."
|
|
36
36
|
},
|
|
37
37
|
{
|
|
38
38
|
"axis_a_value_ref": "val-monolithic",
|
|
@@ -105,7 +105,7 @@
|
|
|
105
105
|
"description": "Decouples content storage from presentation; serves content via an API.",
|
|
106
106
|
"parent_id": "axis-architecture",
|
|
107
107
|
"properties": {
|
|
108
|
-
"rationale": "Headless without the composable extensions
|
|
108
|
+
"rationale": "Headless without the composable extensions: APIs over content but no typed graph guarantee, often without real-time, often with hosted-only editor.",
|
|
109
109
|
"exemplars": ["Contentstack", "Storyblok", "Strapi"],
|
|
110
110
|
"commitments": [
|
|
111
111
|
{ "name": "API-only delivery", "description": "No coupled rendering layer; consumers pull content via REST/GraphQL." },
|
|
@@ -124,7 +124,7 @@
|
|
|
124
124
|
"description": "API delivery plus optional coupled rendering; vendor-managed personalization layer.",
|
|
125
125
|
"parent_id": "axis-architecture",
|
|
126
126
|
"properties": {
|
|
127
|
-
"rationale": "Splits the difference between headless and monolithic
|
|
127
|
+
"rationale": "Splits the difference between headless and monolithic, typically enterprise DXP vendors layering API delivery on top of their incumbent page-bound stack.",
|
|
128
128
|
"exemplars": ["Optimizely", "Sitecore XM Cloud"]
|
|
129
129
|
}
|
|
130
130
|
},
|
|
@@ -191,7 +191,7 @@
|
|
|
191
191
|
"description": "Long-form content as a typed array of typed blocks; rich text without HTML.",
|
|
192
192
|
"parent_id": "axis-editing",
|
|
193
193
|
"properties": {
|
|
194
|
-
"rationale": "Sanity's signature shape
|
|
194
|
+
"rationale": "Sanity's signature shape: long-form authoring without surrendering type guarantees. Each paragraph/heading/quote is a typed block; embedded references are first-class.",
|
|
195
195
|
"exemplars": ["Sanity Studio"],
|
|
196
196
|
"commitments": [
|
|
197
197
|
{ "name": "Typed blocks", "description": "Every paragraph, heading, list, quote is a typed JSON block with stable schema." },
|
|
@@ -227,7 +227,7 @@
|
|
|
227
227
|
"strengths": [
|
|
228
228
|
"Typed content graph with GROQ query language",
|
|
229
229
|
"Real-time CRDT collaboration out of the box",
|
|
230
|
-
"Embeddable studio
|
|
230
|
+
"Embeddable studio, owned inside the team's repo"
|
|
231
231
|
],
|
|
232
232
|
"weaknesses": [
|
|
233
233
|
"Steeper learning curve than form-based headless CMSs",
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
title: "Enterprise Pilot Results
|
|
2
|
+
title: "Enterprise Pilot Results: Q2 2026"
|
|
3
3
|
upg_product: entopo
|
|
4
4
|
upg_version: "0.4.0"
|
|
5
5
|
entity_type: document
|
|
@@ -12,7 +12,7 @@ composition_pattern: experiment_report
|
|
|
12
12
|
graph_source: enterprise-pilot.upg
|
|
13
13
|
---
|
|
14
14
|
|
|
15
|
-
# Enterprise Pilot Results
|
|
15
|
+
# Enterprise Pilot Results: Q2 2026
|
|
16
16
|
|
|
17
17
|
## Background
|
|
18
18
|
|
|
@@ -20,12 +20,12 @@ Our primary persona [[persona:alex-senior-pm]] faces a critical need:
|
|
|
20
20
|
[[need:no-single-source-of-truth|valence:pain|severity:Significant]].
|
|
21
21
|
|
|
22
22
|
This was identified through research that surfaced a key insight:
|
|
23
|
-
{{insight:tool-fragmentation → opportunity:unified-knowledge|informs}}
|
|
23
|
+
{{insight:tool-fragmentation → opportunity:unified-knowledge|informs}},
|
|
24
24
|
our strongest evidence chain from user research to strategic opportunity.
|
|
25
25
|
|
|
26
26
|
[[persona:alex-senior-pm|"Alex"]] leads a 12-person team and
|
|
27
27
|
{{persona:alex-senior-pm -> job:keep-team-aligned|pursues}} alignment as
|
|
28
|
-
a core job
|
|
28
|
+
a core job, but today that job is underserved.
|
|
29
29
|
|
|
30
30
|
## What We Tested
|
|
31
31
|
|
|
@@ -41,7 +41,7 @@ The chain from need to hypothesis:
|
|
|
41
41
|
- The solution proposes
|
|
42
42
|
[[hypothesis:structured-knowledge-reduces-planning]]
|
|
43
43
|
|
|
44
|
-
We ran [[experiment:enterprise-pilot-q2]]
|
|
44
|
+
We ran [[experiment:enterprise-pilot-q2]], a controlled pilot with 5
|
|
45
45
|
enterprise teams over 8 weeks.
|
|
46
46
|
|
|
47
47
|
## Results
|
|
@@ -49,8 +49,8 @@ enterprise teams over 8 weeks.
|
|
|
49
49
|
{{experiment:enterprise-pilot-q2 → learning:planning-time-reduction|produces}}
|
|
50
50
|
|
|
51
51
|
[[learning:planning-time-reduction|"The key learning"]]: teams reduced
|
|
52
|
-
planning time by 22%
|
|
53
|
-
significant. 3 of 5 teams exceeded the 20% threshold.
|
|
52
|
+
planning time by 22% (below the 30% target but statistically
|
|
53
|
+
significant). 3 of 5 teams exceeded the 20% threshold.
|
|
54
54
|
|
|
55
55
|
[[metric:planning-time|current:22%|target:30%]] is trending positive.
|
|
56
56
|
|
|
@@ -77,14 +77,14 @@ The discovery came from the experiment itself:
|
|
|
77
77
|
strong and statistically significant.
|
|
78
78
|
|
|
79
79
|
2. **Adjust the target.** [[metric:planning-time]] target should move
|
|
80
|
-
from 30% to 25
|
|
80
|
+
from 30% to 25%, a more realistic target based on pilot data.
|
|
81
81
|
|
|
82
82
|
3. **Investigate the new need.**
|
|
83
83
|
[[need:context-loss-between-sprints]] is a potential second
|
|
84
84
|
opportunity worth sizing.
|
|
85
85
|
|
|
86
86
|
4. **North star remains.**
|
|
87
|
-
[[objective:reduce-context-switching]] is the right objective
|
|
87
|
+
[[objective:reduce-context-switching]] is the right objective;
|
|
88
88
|
the pilot confirms the direction.
|
|
89
89
|
|
|
90
90
|
## Full Evidence Chain
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
"product": {
|
|
10
10
|
"id": "entopo",
|
|
11
11
|
"title": "Entopo",
|
|
12
|
-
"description": "The product creation tool. Structure your product knowledge as a typed graph
|
|
12
|
+
"description": "The product creation tool. Structure your product knowledge as a typed graph: queryable, traversable, AI-readable.",
|
|
13
13
|
"stage": "mvp"
|
|
14
14
|
},
|
|
15
15
|
"nodes": [
|
|
@@ -170,7 +170,7 @@
|
|
|
170
170
|
"id": "solution_unified-product-graph",
|
|
171
171
|
"type": "solution",
|
|
172
172
|
"title": "Unified Product Graph",
|
|
173
|
-
"description": "A typed knowledge graph that models all product entities
|
|
173
|
+
"description": "A typed knowledge graph that models all product entities (personas, needs, opportunities, solutions, hypotheses, experiments, features, metrics) as nodes with semantic edges. Queryable, traversable, AI-readable.",
|
|
174
174
|
"status": "active",
|
|
175
175
|
"tags": [
|
|
176
176
|
"primary-solution"
|
|
@@ -245,7 +245,7 @@
|
|
|
245
245
|
{
|
|
246
246
|
"id": "learning_planning-time-reduction",
|
|
247
247
|
"type": "learning",
|
|
248
|
-
"title": "22% reduction
|
|
248
|
+
"title": "22% reduction, below target but statistically significant",
|
|
249
249
|
"description": "Teams reduced planning time by 22% (target was 30%). 3 of 5 teams exceeded the 20% threshold. The result is statistically significant and directionally positive, strengthening confidence in the hypothesis.",
|
|
250
250
|
"status": "active",
|
|
251
251
|
"tags": [
|
|
@@ -349,7 +349,7 @@
|
|
|
349
349
|
"target": "need_context-loss-between-sprints",
|
|
350
350
|
"type": "experiment_surfaces_need",
|
|
351
351
|
"properties": {
|
|
352
|
-
"note": "Discovered during pilot
|
|
352
|
+
"note": "Discovered during pilot; not part of original hypothesis"
|
|
353
353
|
}
|
|
354
354
|
},
|
|
355
355
|
{
|
|
@@ -366,10 +366,10 @@
|
|
|
366
366
|
}
|
|
367
367
|
],
|
|
368
368
|
"metadata": {
|
|
369
|
-
"export_name": "Enterprise Pilot
|
|
369
|
+
"export_name": "Enterprise Pilot: UPG Markdown Spec Reference Graph",
|
|
370
370
|
"exported_by": "mr-data",
|
|
371
371
|
"node_count": 12,
|
|
372
372
|
"edge_count": 11,
|
|
373
|
-
"purpose": "Companion graph for UPG-MARKDOWN-v0.1.upg.md
|
|
373
|
+
"purpose": "Companion graph for UPG-MARKDOWN-v0.1.upg.md. Provides resolvable entities for the spec's worked example."
|
|
374
374
|
}
|
|
375
375
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
title: "Decision
|
|
2
|
+
title: "Decision: Ship Smart Search before Q3 Planning"
|
|
3
3
|
upg_product: entopo
|
|
4
4
|
upg_version: "0.4.0"
|
|
5
5
|
entity_type: document
|
|
@@ -24,12 +24,12 @@ We're shipping [[+feature:smart-search|"Smart Search"]] in the v0.2.10 release w
|
|
|
24
24
|
The rationale chain:
|
|
25
25
|
|
|
26
26
|
- [[need:no-single-source-of-truth]] surfaces during planning (every quarter).
|
|
27
|
-
- {{feature:smart-search → metric:weekly-actives|drives}}
|
|
28
|
-
- {{decision:ship-smart-search-q2 → feature:smart-search|approves}}
|
|
27
|
+
- {{feature:smart-search → metric:weekly-actives|drives}}: we expect a 12% lift in weekly actives based on pilot interviews.
|
|
28
|
+
- {{decision:ship-smart-search-q2 → feature:smart-search|approves}}: this decision authorises the work.
|
|
29
29
|
|
|
30
30
|
## Structural properties
|
|
31
31
|
|
|
32
|
-
The decision record has properties that don't fit cleanly inline
|
|
32
|
+
The decision record has properties that don't fit cleanly inline (stakeholders, alternatives considered, blast radius). We use a fenced block:
|
|
33
33
|
|
|
34
34
|
```upg
|
|
35
35
|
{
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
title: "Metric Tracking
|
|
2
|
+
title: "Metric Tracking: Planning Time Reduction (Q2)"
|
|
3
3
|
upg_product: entopo
|
|
4
4
|
upg_version: "0.4.0"
|
|
5
5
|
entity_type: document
|
|
@@ -12,7 +12,7 @@ tags: [metric, q2, validation]
|
|
|
12
12
|
graph_source: ../enterprise-pilot.upg
|
|
13
13
|
---
|
|
14
14
|
|
|
15
|
-
# Planning Time Reduction
|
|
15
|
+
# Planning Time Reduction: Q2 Tracking
|
|
16
16
|
|
|
17
17
|
## Headline
|
|
18
18
|
|
|
@@ -24,8 +24,8 @@ We're below target but trending positive. Statistical significance is confirmed
|
|
|
24
24
|
|
|
25
25
|
The metric decomposes into two input metrics:
|
|
26
26
|
|
|
27
|
-
- [[metric:meeting-count-per-sprint|current:4.2|target:3.0|designation:input]]
|
|
28
|
-
- [[metric:context-handoff-time|current:18m|target:10m|designation:input]]
|
|
27
|
+
- [[metric:meeting-count-per-sprint|current:4.2|target:3.0|designation:input]]: how many planning meetings each team holds per sprint.
|
|
28
|
+
- [[metric:context-handoff-time|current:18m|target:10m|designation:input]]: time spent re-establishing context at sprint boundaries.
|
|
29
29
|
|
|
30
30
|
Both are moving in the right direction. Meeting count is at 4.2 (down from 6.1 baseline); context handoff is at 18 minutes (down from 27 minutes).
|
|
31
31
|
|
|
@@ -39,7 +39,7 @@ During pilot week 6, the team surfaced a previously unknown input we should add
|
|
|
39
39
|
|
|
40
40
|
[[+metric:re-planning-incidents|current:1.4|target:0.5|designation:input|"Times per sprint a team has to redo planning because of context loss"]].
|
|
41
41
|
|
|
42
|
-
This is a creation reference
|
|
42
|
+
This is a creation reference. The first occurrence in this document declares the metric; it enters the graph at next sync.
|
|
43
43
|
|
|
44
44
|
## Quality assessment
|
|
45
45
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
title: "Alex (Senior PM)
|
|
2
|
+
title: "Alex (Senior PM): Persona Profile"
|
|
3
3
|
upg_product: entopo
|
|
4
4
|
upg_version: "0.4.0"
|
|
5
5
|
entity_type: document
|
|
@@ -19,4 +19,4 @@ status: published
|
|
|
19
19
|
|
|
20
20
|
## What gets in her way
|
|
21
21
|
|
|
22
|
-
The biggest blocker is [[need:no-single-source-of-truth|valence:pain|severity:Significant]]
|
|
22
|
+
The biggest blocker is [[need:no-single-source-of-truth|valence:pain|severity:Significant]]: context lives in seven tools and nobody owns reconciling them.
|