You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: docs/g-track/prd-ground-as-ontology.md
+93-5Lines changed: 93 additions & 5 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -113,7 +113,7 @@ behaviour.**
113
113
114
114
| Component | Source | Note |
115
115
|---|---|---|
116
-
| Ontology vocabulary | product-cli's existing RDF vocabulary |**Assumption A1:** the axis registry uses this vocabulary, extended with act-relevant properties, not a separate one. Open ruling 25; the PRD takes the extend position. If ruled otherwise, §7.2 changes and nothing else does. |
116
+
| Ontology vocabulary | product-cli's existing RDF vocabulary |**Assumption A1:** the axis registry uses this vocabulary, extended with act-relevant properties, not a separate one. Open ruling 25; the PRD takes the extend position. If ruled otherwise, §7.2 changes and nothing else does. The registry vocabulary gains tick rate as a property of entities and axes (§5.6), carried as a Reading like any other ground. It is not a caching parameter and is not editable outside the proposal path. |
117
117
|**Registry authority**| a dedicated **registry repository** per instance, generated from the versioned **registry template***(re-typed at G-1 Gate 3: `docs/g-track/registry-template/`; the first instance generates at G0 entry with its parameters — owner, name, base IRI, ratifier — supplied then)*| canonical store of ratified triples; per-triple files in Turtle (the per-claim file pattern — the pattern transfers, the format was never the load-bearing part; Gate 3 ruling); ratification by PR merge; supersession, never rewriting; CI runs SHACL on every change; the founding-decision slot is the instance's first ratified content. **Not** inside any codebase and **not** inside the framework canon repos — it is the owning organisation's ground, not the framework's. |
118
118
| **Registry serving** | SPARQL endpoint rebuilt from the registry repo at each merge | read-only; **pinned to a ref** — every Reading served carries the ref, giving Q11 as-of semantics with no extra machinery. Local mode: product-cli embeds a triple store (Oxigraph — Rust, SPARQL 1.1, fits the workspace natively) over a pinned clone; works offline. Central mode: the same store or Fuseki/GraphDB in Azure Container Apps behind Entra ID — the O-track stack arriving early. Store choice is swappable because **the endpoint is a projection of the repo, not the source** (Q30's diagnostic, applied to our own database). **Inference runs at projection build**: entailments are recomputable, so they never enter the authority repo — each endpoint rebuild derives the inferred graph for that ref, every entailed triple `prov:wasDerivedFrom` the asserted triples plus the rule id, assurance = the rule. The repo stays pure assertion; inference inherits as-of discipline for free. *(Verified at G-1, 2026-08-17:)* Oxigraph holds — 0.5.9 (2026-06-18), active ~monthly cadence, SPARQL 1.1 Query/Update/Federated, full named-graph support; honest risk signal is a bus-factor of ~1. ~~**The workspace's `oxigraph = "0.4"` pin is a dead line**~~ (last 0.4.11, 2025-05-21; 0.5.0 shipped 2025-09-13 as a breaking line) — **discharged 2026-08-17, before G0 entry**: the upgrade landed as PR #46 (`product-core` now pins `oxigraph = "0.5"`, with `pf::query`, `pf::seed` and `pf::sparql_rules` migrated to the 0.5 API). The stale-ground finding in our own ground is closed; what remains is the standing obligation not to let the pin drift again. *(Ruled at G-1 Gate 2:)* inference mechanism is **CONSTRUCT-to-fixpoint on Oxigraph as primary** — it reuses the `pf::sparql_rules` shape already in the codebase and adds no dependency — with the Rust `reasonable` crate (0.4.4, BSD-3) as the named fallback; recorded as track decision `g-dec-02` with a `revisit_if`: fixpoint wall-time exceeding an acceptable projection-build budget at G0 scale flips to the fallback. The no-benchmark hedge is discharged by measuring at G0, not by choosing conservatively now. |
119
119
| Validation | SHACL shapes, SPARQL | as-is; shapes gain the act properties in §4.2 |
@@ -544,7 +544,7 @@ extractor is built re-runnable from day one because it costs nothing then and ev
544
544
### 5.5.1 Review is batched by the pair, with the derivation as the sub-key
545
545
546
546
*(Added 2026-08-20.)* Per-triple review does not scale: 561 files was already at the edge of it and
547
-
the full solution is ≈16.7× that corpus. Wholesale merge is manufactured ground by §5.6, so the
547
+
the full solution is ≈16.7× that corpus. Wholesale merge is manufactured ground by §5.7, so the
548
548
answer is neither of those — it is **review by kind**.
549
549
550
550
A **batch** is the set of assertions sharing a derivation signature:
@@ -577,8 +577,8 @@ merged reads as acceptance of a reviewed set, and what was actually ratified was
577
577
superset.
578
578
579
579
This is `term:presumed-discharge` at the ratifier's seat rather than in an instrument: a record
580
-
state where a pass is indistinguishable from a skip. It is also the rubber-stamp failure §5.6 exists
581
-
to forbid, arriving through the one path §5.6 did not describe — not wholesale merge *instead of*
580
+
state where a pass is indistinguishable from a skip. It is also the rubber-stamp failure §5.7 exists
581
+
to forbid, arriving through the one path §5.7 did not describe — not wholesale merge *instead of*
582
582
review, but wholesale merge *after* review, which looks like the discharged form and is not.
583
583
584
584
Binding from here:
@@ -598,7 +598,72 @@ rewrite, and it is a ratifier's act with a ruling behind it, never an instrument
598
598
record landed; they are now two queries (§5.2). The argument for recording derivation was made in
599
599
the abstract; this is the first real defect in the ratified set it has repaid.
600
600
601
-
### 5.6 Guard
601
+
### 5.6 Tick rate and the validity horizon
602
+
603
+
**The claim.** An entity's expected rate of change is ground about that entity. Held in the registry
604
+
rather than in a caching layer, it makes read-versus-cache a computed decision rather than a
605
+
judgement — and it makes the same question answerable at design time, before any system runs.
606
+
607
+
**The computation, and where each input lives.**
608
+
609
+
| Input | Held by | Note |
610
+
|---|---|---|
611
+
|`as_of`| the Reading (§4.1) | already carried |
612
+
| tick rate | the **entity or axis** in the registry | this addendum's addition |
613
+
| tolerance τ | the **act**| not the entity — see below |
614
+
|**validity horizon**| computed, per act | the age at which expected drift exceeds what this act tolerates |
615
+
616
+
**Tolerance sits on the act, and that is the load-bearing part.** The same entity read for two
617
+
different acts may have two different acceptable stalenesses: a display may tolerate an hour where a
618
+
settlement tolerates none. So the horizon is a function of the *pair*, never of the entity alone.
619
+
This is v5.7.0's act-indexed discharge (`DDD-frame-16`) applied to freshness — a reading is fresh
620
+
*for an act*, not fresh in general.
621
+
622
+
**The tick rate is itself a Reading, and this is what lets the system be designed before it runs.**
623
+
The same four-tuple as any other ground:
624
+
625
+
| Stage | value | provenance | assurance |
626
+
|---|---|---|---|
627
+
| Design time | the expected rate |`declared`*(not in §4.1's value set — open item 21)*| low — an assumption by whoever declared it |
628
+
| Running system | the observed rate |`observed`| higher — measured over retained acts |
629
+
630
+
So design-time assumptions are not a separate mode of the system. They are the same field at lower
631
+
assurance, superseded when observation arrives. **The gap between declared and observed is
632
+
measurable** — the proxy-fidelity check applied to the drift model itself: a rate was declared, a
633
+
rate was observed, and the divergence is a finding rather than an embarrassment.
634
+
635
+
**Observation is nearly free where the arrangement is event-sourced.** The event stream is the tick
636
+
record; rate per entity is a query over retained acts. This is the same argument retention always
637
+
makes — retained events answer questions nobody planned for, and this is one of them.
638
+
639
+
**It makes co-drift computable.** Clustering by co-drift and ordering by rate has been a heuristic
640
+
for domain modelling. With rates on entities it is a measurement, and cache boundaries — what
641
+
invalidates together — fall out of the registry rather than out of intuition.
642
+
643
+
### 5.6.1 Three constraints on the model
644
+
645
+
**Rate is a distribution, not a scalar.** Many entities change in bursts, and a mean rate silently
646
+
under-serves exactly the moments that matter. The cheap form is a scalar; the honest form carries
647
+
burstiness. Whichever is taken, the vocabulary must record **which form a given rate is**, so a
648
+
consumer never reads a mean as though it were a bound.
649
+
650
+
**It is ground, not a tuning knob.** The value of a tick rate is that it carries provenance and
651
+
assurance and is consumed by caching decisions. The moment it becomes a parameter someone edits for
652
+
performance, it stops being ground and every horizon computed from it stands on a number nobody
653
+
filed. Rate changes are proposals, reviewed like any other assertion.
654
+
655
+
**Bootstrap honestly.** Declared rates are proxies over open predicates — the same structure as the
656
+
proxy-predicate gap. That is legitimate and better than nothing, on two conditions: they are marked
657
+
`declared`, and they are **superseded** rather than left in place once observation is available. A
658
+
declared rate still governing after a year of observation is the proxy-predicate gap in miniature.
659
+
660
+
### 5.6.2 What this replaces
661
+
662
+
Data as a separate specification domain. There is no data layer holding freshness policy: there are
663
+
entities carrying rates, acts carrying tolerances, and horizons computed from the pair. Caching
664
+
configuration becomes a *projection* of that, regenerated when either side moves — not a source.
665
+
666
+
### 5.7 Guard
602
667
603
668
The reviewer's acceptance path is **per triple, never per run**. A single review of a large codebase
604
669
that accepts wholesale is a rubber stamp, and rubber-stamped ground is manufactured ground.
@@ -998,6 +1063,29 @@ Emil's rulings needed, in order of how much they change the design:
998
1063
Propose the retry shape — how many attempts, how spaced, how the attempts are written into the
999
1064
run evidence so the verdict's assurance is visible — and rule on it before any row's gating
1000
1065
depends on an operation that has ever timed out.
1066
+
18.**Tick-rate vocabulary shape** — scalar versus distribution, the unit, and how burstiness is
1067
+
expressed where it is carried. Emil rules before implementation; the model's honesty depends on
1068
+
a consumer never mistaking a mean for a bound.
1069
+
19.**Where tolerance is declared.** The horizon needs τ per act, and the act-site extractors do not
1070
+
currently carry one. Whether tolerance is declared per act kind, per decision, or per act at
1071
+
declaration time is a design ruling, and it gates any implementation of §5.6.
1072
+
20.**Observation source.** Rate observation assumes retained acts to count. For arrangements that
1073
+
are event-sourced this is a query; for those that are not, it is unavailable and rates stay
1074
+
`declared` indefinitely. State that limit rather than implying observation is always reachable.
1075
+
21.**Design-time provenance** — *(opened 2026-08-20 by the tick-rate addendum; a defect in the
1076
+
addendum itself, of the same class as the G-1 mis-pin — a value used from conversation as
1077
+
though it were filed.)* §5.6's stage table gives declared rates `provenance = declared`, which
1078
+
is **not in §4.1's value set** (`controlled` / `observed` / `inferred` / `institutional`).
1079
+
Three candidate resolutions: (a) **a fifth value** — a filing consequence, since the set is
1080
+
track-owned under `g-dec-01` pending the Q25/Q27/Q30 wave, and this would be a second consumer
1081
+
waiting on that wave alongside the existing one; (b) **`inferred`**, with the assumption
1082
+
recorded in `assurance` rather than `provenance`; (c) **a distinct axis** for whether a value
1083
+
was assumed or measured, on the grounds that assumed-versus-measured may be orthogonal to where
1084
+
a value came from — "assumed at design time" and "inferred by rule" are different things, and
1085
+
forcing them into one column is the conflation §5.2's second axis was added to correct. Emil
1086
+
rules, with the wave's context; gates any implementation of §5.6. **Deliberately not folded
1087
+
into item 18**: 18 is the rate's shape and stays inside the G-track, 21 is whether the
1088
+
provenance value set gains a member and carries a canon consequence.
0 commit comments