@unified-product-graph/core 0.30.0 → 0.32.0
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 +64 -0
- package/README.md +1 -1
- package/dist/index.cjs +2013 -266
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +12139 -10650
- package/dist/index.d.ts +12139 -10650
- package/dist/index.js +2009 -266
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,66 @@ This project uses [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
|
7
7
|
|
|
8
8
|
---
|
|
9
9
|
|
|
10
|
+
## [0.32.0] - 2026-08-21
|
|
11
|
+
|
|
12
|
+
**A graph can now hold a real issue tracker's corpus without losing anything, and a query-driven view can say what it is a view OF.** Nine items in one design cycle: the two shapes the D-track held for "the next minor" (F1's query declaration, Q4b's artifact record) plus the six asks from a measured 1,032-issue Linear-parity audit. Additive throughout; three migrations registered, every one with a live population of zero.
|
|
13
|
+
|
|
14
|
+
### Added
|
|
15
|
+
- **`capture`** (ent_362, `proposed`, lifecycle-free, containment-free) + **`capture_renders_node`** (cross-domain, polymorphic). A dated, hashed rendition of something already in the graph: a screenshot, an export, a PDF. The subject stays a graph node; the capture says what it looked like at a moment and how to tell whether it still does. Deliberately NOT named `artifact` — that word already means `workflow_artifact` here and an inline-content document store in at least one consumer, and a third meaning is how a vocabulary stops being one. Extending `document` fails the dual-shape gate three ways (it has the PUBLISHING lifecycle, no hash, no captured-at, and a typed subject-matter edge family that is not a rendition relation); extending `workflow_artifact` would force a phantom `workflow_run` per file, since that is its only structural parent.
|
|
16
|
+
- **`UPGBaseNode.key`** — the stable, human-citable handle (`LTN-311`), unique within the product ACROSS types, immutable once assigned, never reused. Not `slug`: a slug is unique within `(product_id, type)` and auto-derives from `title`, so two types could legally hold one key and a retitle would break every citation. Not `external_id`: that records where a node CAME from and is structurally incapable of minting the next one. Paired with **`product.key_prefix`**; no counter is serialised, because the next number is `max + 1` from the graph and a counter is a fact about a store rather than about the product.
|
|
17
|
+
- **`UPGBaseNode.archived` / `archived_at`** — archive as an axis ORTHOGONAL to `status`. Generalised from `WorkspaceProperties`, which shipped the same pair for one type. Field data says it is general: a tracker held 559 archived-completed items beside 18 live-completed ones, and every existing `archived` LIFECYCLE PHASE is `status_category: 'completed'`, so in the six-bucket read the two were indistinguishable. Default-read convention (archived excluded from default views, always queryable) is documented, not enforced.
|
|
18
|
+
- **`node_assigned_to_person`** (cross-domain, polymorphic). Assignment is not ownership, and this REVERSES the 0.12.0 rule that routed `task`/`bug` `assignee` into `node_owned_by_person`. Assignment carries an interval and an exclusivity ownership does not, and a real board ran 85% unassigned while every item was owned — a state one edge cannot express. Existing `node_owned_by_person` edges are deliberately NOT rewritten: on a task, one is indistinguishable from genuine ownership by inspection, so a blanket rename would reclassify real facts. `user_story` gains the promotion rule it never had.
|
|
19
|
+
- **`product_dimensioned_by_classification_axis`** (hierarchy). One level of label grouping needs NO new label surface: `classification_axis` + `classification_value` + `node_classified_as_classification_value` have been `stable` since 0.4.0 and are strictly better than a `tag` entity (edge-level rationale, declared cardinality, cross-product eligible). The only thing missing was a home — the axis's sole parent was `competitive_analysis`. The line between the two mechanisms: **if the group has a name a person would filter by, it is an axis; otherwise it is a tag.**
|
|
20
|
+
- **`UPGViewQuery` / `UPGViewPresentation` / `UPGViewPredicate`**, with `member_query` and `presentation` on `composition` and `derived` on its members (F1's shape). The location was ruled at 0.31.0; this is the shape, and it extends `composition` rather than minting a view entity, because a composition is already named, slugged, published, revisioned and shared. Selection is portable and travels; presentation is advisory and a consumer may ignore all of it. `derived` discharges the field finding that auto-admitted members were being counted as authored content — membership arrives by query, position is authored, and a signature meant to answer "did a person change this" must exclude the former.
|
|
21
|
+
- **`backlog` on the WORK_ITEM lifecycle.** The template reached four of the six `StatusCategory` buckets, and the cost was arithmetic rather than theoretical: a source "Backlog" normalised to a phase this template does not have, importers omit what they cannot map, and roughly 195 of a measured 1,032-issue corpus arrived carrying no status at all. NO `triage` phase — that bucket is reachable through INCIDENT and DISCOVERY, where triage is actually practised, and a task nobody has accepted is a task in `backlog`. `initial_phase` deliberately stays `todo`: moving it would change what every existing graph's next node means.
|
|
22
|
+
|
|
23
|
+
### Changed
|
|
24
|
+
- **`planning_cycle_schedules_user_story` → `planning_cycle_schedules_work_item`**, widened to the polymorphic work-item endpoint by the same construction `work_item_blocks_work_item` used in the same 0.20.0 batch. The story-only endpoint could not hold a tracker import, because importers default an unrecognised issue to `task` — the one type a cadence could not reach. Registered rename; no flip. The `planning-cycle-without-scheduled-work` anti-pattern is retargeted with it, or a cycle full of tasks would have reported as empty.
|
|
25
|
+
- **`workflow_state_category` narrowed from `string` to `StatusCategory`** on all five carriers (`feature`, `epic`, `user_story`, `task`, `bug`). The field exists to carry exactly that vocabulary; an open string meant nothing enforced the one thing it was for. A side effect worth having: the generated runtime schema now emits the six bucket values as `enum` for the first time.
|
|
26
|
+
- **`RelationshipCheck.target_type` admits the wildcard**, and the presence collector records polymorphic edges under BOTH the concrete and the wildcard key. Half of this is a type widening; the other half is a latent false-positive class — the index is keyed by concrete endpoint types, so a check declaring `'node'` would have matched nothing, and for a `not_exists` comparison matching nothing means firing on every correct graph.
|
|
27
|
+
- The one-release read tolerance for the pre-0.31.0 underscore canvas key **retires as scheduled**. Preservation is unaffected: the key is no longer read, and still carried byte for byte.
|
|
28
|
+
|
|
29
|
+
### Deprecated
|
|
30
|
+
- **`WorkspaceProperties.archived` / `archived_at`** → the base-node pair, lifted by `UPG_PROPERTY_MIGRATIONS['0.32.0']`.
|
|
31
|
+
- **`TaskProperties.labels` / `BugProperties.labels`** → dropped. A duplicate of base-node `tags` with no consumers anywhere; three parallel label surfaces were two too many.
|
|
32
|
+
|
|
33
|
+
### Fixed
|
|
34
|
+
- `WorkspaceProperties` documented its parent edge as `product_contains_workspace`, which has never existed. The real edge is `product_thinks_in_workspace`, with `organization_` and `product_area_` siblings per altitude.
|
|
35
|
+
- The 0.31.0 CHANGELOG named the migrated canvas key `entopo:views`; the writer and its own contract test both use `entopo:view_blocks`. A shipped CHANGELOG cannot be recalled from npm, so the correction rides here.
|
|
36
|
+
|
|
37
|
+
### Notes
|
|
38
|
+
- Truth: **324 entities · 1082 edges · 69 cross-edges · 25 anti-patterns · 98 tools · 334 phases**. Zero new tools. Zero new checks — three invariants (`key` uniqueness, one active cycle per parent, archived-excluded-by-default) are DEFINED and unenforced, each with a stated pull-forward condition, because a check without a graded corpus is one nobody can defend.
|
|
39
|
+
- Edge arithmetic, as the cheapest check that design and build agree: +1 hierarchy, +2 cross-domain, semantic unchanged because the cadence edge was renamed rather than added. 452→453h, 421→423x.
|
|
40
|
+
- Polymorphic edge families: **13 (24 entries)**. Assignment is registered as its OWN family rather than folded into universal ownership, so a future author who merges them does it visibly.
|
|
41
|
+
- One new `(source, target, classification)` collision, and it IS the design: `node → person / cross-domain` now carries both `owned_by` and `assigned_to`. Verified as the only one; the other three new edges collide with nothing.
|
|
42
|
+
- The retargeted anti-pattern ships a labeled fixture set including the near-miss it was most likely to misjudge — a coarse `period` cycle that schedules nothing directly and only nests finer cycles.
|
|
43
|
+
|
|
44
|
+
---
|
|
45
|
+
|
|
46
|
+
## [0.31.0] - 2026-08-19
|
|
47
|
+
|
|
48
|
+
**The eval harness gets the four spec affordances its architecture brief asked for, and the workspace canvas learns what a tool-owned key is.** Two threads converge: the eval-architecture design cycle (ratified 2026-08-16) needed benchmarks that can name what they measure and runs that can carry more than one number; and the image-artifact pilot found two namespacing conventions already coexisting in one canvas bag, with the spec silent on which was right. Additive; no breaking change; no migration of any `.upg` file.
|
|
49
|
+
|
|
50
|
+
### Added
|
|
51
|
+
- **`eval_benchmark_measures_node`** (semantic, polymorphic). A benchmark names its SUBJECT by pointing at it: a tool, a document, a check, an importer, a feature. The wildcard is deliberately wider than the truth (a benchmark cannot meaningfully measure a persona); that over-width is stated on the label as an honest deferral of "what is a tool in the graph", which this release does not answer. Coexists with the typed `eval_benchmark_measures_feature` on the `constraint_constrains_feature` / `node_constrains_node` precedent.
|
|
52
|
+
- **`eval_benchmark_draws_cases_from_ai_dataset`** (semantic). A labeled corpus IS an `ai_dataset`; this is the one join edge that makes it so, per the recurrence discipline that tries the existing type before minting one.
|
|
53
|
+
- **`metric_scores` on `eval_run`** — an exported `MetricScore[]` (`metric`, `value`, `sample_size`), so a run reports precision AND recall as separate numbers instead of one aggregate `score` or a stringly-typed pair. `value` is normalized 0 through 1 (1 best) because comparing runs is the entire reason the array exists and two runs on different raw scales do not compare; non-rate measurements (wall-clock, tokens, cost) stay on their typed fields. `sample_size` is required: a sampled run reports its sample size beside its score, always, so a comparison across runs can never quietly compare different sample sizes.
|
|
54
|
+
- **`benchmark_type` widened** with `precision_recall`, `task_success`, `coherence`. The enum is a DIMENSION axis (what kind of number); the subject axis lives on `eval_benchmark_measures_node`. Do not add subject-shaped values here — they would encode on the dimension axis what the edge already carries, and the two would drift.
|
|
55
|
+
- **Namespaced keys on the workspace canvas.** The rule, now in spec: a tool-owned key is `<tool>:<key>` (colon, because an underscore key is indistinguishable from an ordinary property name — which is also why no validator can police this rule, and enforcement is documentation plus the type); every consumer preserves unknown keys byte for byte; **no consumer interprets a key it does not own** — preservation is a storage guarantee that says nothing about meaning. `WorkspaceCanvas` carries a template-literal index signature encoding the colon form at compile time.
|
|
56
|
+
- **`composition` type-scope sentence** (F4) clarifying which entity kinds an identity rule reaches.
|
|
57
|
+
|
|
58
|
+
### Changed
|
|
59
|
+
- The driving query of a query-driven layer is declared in spec, not in a bag key — a consequence of the no-foreign-interpretation rule: a bag-held query would make every future gallery proprietary to one application. The LOCATION is ruled here; the SHAPE is held for the next minor, since the field pilot measured that the hole exists, not what fills it.
|
|
60
|
+
- `entopo_views` (underscore) migrates to `entopo:view_blocks` (colon) in the same window as this release, executed by the Entopo Local lane: same-day rename, one release of tolerant reading for dev-written files carrying the old form, tolerance retiring at 0.32.0. Tolerance converts an undetectable failure into a scheduled one.
|
|
61
|
+
|
|
62
|
+
### Notes
|
|
63
|
+
- Truth: 323 entities · 1079 edges · 69 cross-edges · 25 anti-patterns · 98 tools. Zero new checks; the syntax rule introduces none because none could see the half that matters.
|
|
64
|
+
- Polymorphic edge families: 10 (21 entries), asserted as data in the spec-integrity test (a `FAMILIES` record that must partition the array exactly).
|
|
65
|
+
- Fixture coverage: both new edges carry saturated-graph instances; `eval_benchmark_measures_node` points at an `api_endpoint` deliberately, so the example teaches the wildcard where the typed feature edge does not belong.
|
|
66
|
+
- The 0.30.0 package shipped a CHANGELOG whose `[0.29.0]` heading had been lost to a release-prep edit; this release carries the corrected ladder.
|
|
67
|
+
|
|
68
|
+
---
|
|
69
|
+
|
|
10
70
|
## [0.30.0] - 2026-08-15
|
|
11
71
|
|
|
12
72
|
**A surface tree is often not one tree but a family of trees selected by configuration, and the graph can now say so.** A feature flag, a plan tier, a permission level or a beta programme changes which surfaces exist and what contains what; until now every surface fact was implicitly qualified by "in whatever configuration someone happened to be looking at", unrecorded. The stored graph is now the union of that family, a single configuration is a projection of it, unqualified facts are invariant, and a graph declaring no variance is semantically identical to before. Zero migration; additive; no breaking change.
|
|
@@ -26,6 +86,10 @@ This project uses [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
|
26
86
|
### Notes
|
|
27
87
|
- Truth: 322 entities · 1073 edges · 69 cross-edges · 98 tools. Zero new anti-patterns — the drift checks carry the invariants, and a detector with no field evidence behind it is how a check family gets noisy.
|
|
28
88
|
|
|
89
|
+
---
|
|
90
|
+
|
|
91
|
+
## [0.29.0] - 2026-08-15
|
|
92
|
+
|
|
29
93
|
**The contention check learns to read `capacity`, violations learn to name their nodes, and a batch write learns to un-say a property.** All three came from the same field reporter measuring the check on a real 43-surface graph: 10 surfaces flagged, 7 correctly, 3 falsely — and every false positive had an occupant count at or below its stated capacity. A surface whose occupants all fit is partitioned, not contended. Additive; no breaking change.
|
|
30
94
|
|
|
31
95
|
### Changed
|
package/README.md
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
The TypeScript core for the **Unified Product Graph (UPG)**, an open specification that gives product tools a shared vocabulary for entities, edges, and frameworks.
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
324 entity types across 37 domains. 1082 typed edges. 53 canonical framework definitions, with more added as each is reviewed.
|
|
11
11
|
|
|
12
12
|
## Install
|
|
13
13
|
|