Skip to content

Commit c1557a3

Browse files
committed
StampCalculator: getDefault/getTemplate; version-iteration exclusion
Implements the decided defaults/templates contract. DefaultsTemplateTerm (terms module) declares the seam identities -- Default value concept, Template concept, and the Defaults and templates module (regular name 'Defaults') -- each derived exactly as the IkeFoundation ledger derives birth-FQN identities (T5 of the set UUID and the FQN), so tinkar-core's constants equal what ike-terms mints; one-line swappable pending any rename before the content lands. getDefault(pattern) and getTemplate(purpose) resolve directly by the stock singleSemanticUuid(pattern, attachment) identity and return latest at the caller's position, so per-path preference override and retirement come from ordinary path calculus. The one-arg getTemplate accepts only the semantic carrying its own computed identity and throws on cross-pattern ambiguity, directing to the two-arg form. Absent the accessors, defaults/template semantics are excluded from version-iteration operations only: iteration surfaces route through an uncached latest variant whose stamp evaluation treats a version in the Defaults and templates module as not on route. Chronology enumeration, latest(nid)/latest(Entity), version graphs, and nid-level surfaces are untouched -- store truth; it is the computation of iteration over versions that triggers the exclusion. DefaultsTemplateCalculatorIT (real ephemeral store, 5 scenarios) covers computed-identity retrieval, template retrieval, iteration exclusion with chronology inclusion, child-path override, and retirement without resurrection. Refs: IKE-Network/ike-issues#886
1 parent 2673c9f commit c1557a3

4 files changed

Lines changed: 715 additions & 9 deletions

File tree

entity/src/main/java/dev/ikm/tinkar/coordinate/stamp/calculator/StampCalculator.java

Lines changed: 208 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import dev.ikm.tinkar.common.service.PrimitiveDataSearchResult;
2323
import dev.ikm.tinkar.common.util.functional.QuadConsumer;
2424
import dev.ikm.tinkar.common.util.functional.TriConsumer;
25+
import dev.ikm.tinkar.common.util.uuid.UuidT5Generator;
2526
import dev.ikm.tinkar.component.ConceptVersion;
2627
import dev.ikm.tinkar.coordinate.Coordinates;
2728
import dev.ikm.tinkar.coordinate.navigation.calculator.NavigationCalculator;
@@ -35,6 +36,7 @@
3536
import dev.ikm.tinkar.entity.graph.DiTreeVersion;
3637
import dev.ikm.tinkar.entity.graph.VersionVertex;
3738
import dev.ikm.tinkar.terms.ConceptFacade;
39+
import dev.ikm.tinkar.terms.DefaultsTemplateTerm;
3840
import dev.ikm.tinkar.terms.EntityFacade;
3941
import dev.ikm.tinkar.terms.PatternFacade;
4042
import org.eclipse.collections.api.factory.Lists;
@@ -50,14 +52,42 @@
5052
import java.util.Objects;
5153
import java.util.Optional;
5254
import java.util.OptionalInt;
55+
import java.util.UUID;
5356
import java.util.concurrent.atomic.AtomicInteger;
5457
import java.util.function.BiConsumer;
5558
import java.util.stream.Stream;
5659

5760
import static dev.ikm.tinkar.terms.TinkarTerm.STAMP_PATTERN;
5861

62+
/**
63+
* Computes latest versions of components at a stamp coordinate's position.
64+
*
65+
* <h2>Defaults/template exclusion</h2>
66+
* Default value semantics and template semantics (IKE-Network/ike-issues#886) live in
67+
* {@link DefaultsTemplateTerm#DEFAULTS_AND_TEMPLATES_MODULE} — every version of a
68+
* defaults/template chronology is in that module, and that module holds only
69+
* defaults/template content. Version-iteration operations (the
70+
* {@code streamLatestVersionForPattern} and {@code forEachSemanticVersion*} family)
71+
* exclude versions stamped in that module, so defaults and templates never surface as
72+
* ordinary pattern or component content. Chronology-level and nid-level surfaces are
73+
* unchanged (store truth): chronology enumeration still returns defaults/template nids,
74+
* and {@link #latest(int)} on such a nid still resolves. The dedicated accessors —
75+
* {@link #getDefault(PatternFacade)}, {@link #getTemplate(ConceptFacade)} — include the
76+
* module and resolve by computed identity.
77+
*/
5978
public interface StampCalculator {
6079
Logger LOG = LoggerFactory.getLogger(StampCalculator.class);
80+
81+
/**
82+
* Streams the latest version of each semantic of the given pattern at this
83+
* calculator's position — a version-iteration operation: versions stamped in
84+
* {@link DefaultsTemplateTerm#DEFAULTS_AND_TEMPLATES_MODULE} are excluded, so a
85+
* defaults/template semantic of the pattern contributes an empty {@link Latest}.
86+
*
87+
* @param patternFacade the pattern whose semantics to stream
88+
* @return one {@link Latest} per semantic chronology of the pattern; empty entries
89+
* for semantics with no reachable, allowed-state, non-defaults version
90+
*/
6191
default Stream<Latest<SemanticEntityVersion>> streamLatestVersionForPattern(PatternFacade patternFacade) {
6292
return streamLatestVersionForPattern(patternFacade.nid());
6393
}
@@ -110,7 +140,17 @@ static RelativePosition getRelativePositionTimeOnly(int stampNid1, int stampNid2
110140
StampCoordinate stampCoordinate();
111141

112142

113-
Stream<Latest<SemanticEntityVersion>> streamLatestVersionForPattern(int patternNid);
143+
/**
144+
* Streams the latest version of each semantic of the given pattern at this
145+
* calculator's position — a version-iteration operation: versions stamped in
146+
* {@link DefaultsTemplateTerm#DEFAULTS_AND_TEMPLATES_MODULE} are excluded, so a
147+
* defaults/template semantic of the pattern contributes an empty {@link Latest}.
148+
*
149+
* @param patternNid the nid of the pattern whose semantics to stream
150+
* @return one {@link Latest} per semantic chronology of the pattern; empty entries
151+
* for semantics with no reachable, allowed-state, non-defaults version
152+
*/
153+
Stream<Latest<SemanticEntityVersion>> streamLatestVersionForPattern(int patternNid);
114154

115155
default Stream<SemanticEntityVersion> streamLatestActiveVersionForPattern(PatternFacade patternFacade) {
116156
return streamLatestActiveVersionForPattern(patternFacade.nid());
@@ -266,17 +306,54 @@ default void forEachSemanticVersionOfPattern(PatternFacade patternFacade,
266306

267307
}
268308

309+
/**
310+
* Applies the procedure to the latest version of each semantic of the given pattern
311+
* at this calculator's position — a version-iteration operation: versions stamped in
312+
* {@link DefaultsTemplateTerm#DEFAULTS_AND_TEMPLATES_MODULE} are excluded, so
313+
* defaults/template semantics of the pattern are never presented.
314+
*
315+
* @param patternNid the nid of the pattern whose semantics to iterate
316+
* @param procedure receives each latest semantic version with the pattern's latest version
317+
*/
269318
void forEachSemanticVersionOfPattern(int patternNid, BiConsumer<SemanticEntityVersion, PatternEntityVersion> procedure);
270319

320+
/**
321+
* Parallel form of {@link #forEachSemanticVersionOfPattern(int, BiConsumer)} — the
322+
* same version-iteration contract, including the exclusion of versions stamped in
323+
* {@link DefaultsTemplateTerm#DEFAULTS_AND_TEMPLATES_MODULE}.
324+
*
325+
* @param patternNid the nid of the pattern whose semantics to iterate
326+
* @param procedure receives each latest semantic version with the pattern's latest version
327+
*/
271328
void forEachSemanticVersionOfPatternParallel(int patternNid, BiConsumer<SemanticEntityVersion, PatternEntityVersion> procedure);
272329

330+
/**
331+
* Parallel form of {@link #forEachSemanticVersionOfPattern(int, BiConsumer)}
332+
* restricted to the given semantic nids — the same version-iteration contract,
333+
* including the exclusion of versions stamped in
334+
* {@link DefaultsTemplateTerm#DEFAULTS_AND_TEMPLATES_MODULE}.
335+
*
336+
* @param semanticNidSet the semantic nids to consider
337+
* @param patternNid the nid of the pattern whose semantics to iterate
338+
* @param procedure receives each latest semantic version with the pattern's latest version
339+
*/
273340
void forEachSemanticVersionInSetOfPatternParallel(ImmutableIntSet semanticNidSet, int patternNid, BiConsumer<SemanticEntityVersion, PatternEntityVersion> procedure);
274341

275342
default void forEachSemanticVersionForComponent(EntityFacade component,
276343
BiConsumer<SemanticEntityVersion, EntityVersion> procedure) {
277344
forEachSemanticVersionForComponent(component.nid(), procedure);
278345
}
279346

347+
/**
348+
* Applies the procedure to the latest version of each semantic referencing the given
349+
* component at this calculator's position — a version-iteration operation: versions
350+
* stamped in {@link DefaultsTemplateTerm#DEFAULTS_AND_TEMPLATES_MODULE} are
351+
* excluded, so defaults/template semantics attached to the component are never
352+
* presented.
353+
*
354+
* @param componentNid the nid of the referenced component
355+
* @param procedure receives each latest semantic version with the component's latest version
356+
*/
280357
void forEachSemanticVersionForComponent(int componentNid,
281358
BiConsumer<SemanticEntityVersion, EntityVersion> procedure);
282359

@@ -286,6 +363,18 @@ default void forEachSemanticVersionForComponentOfPattern(EntityFacade component,
286363
forEachSemanticVersionForComponentOfPattern(component.nid(), patternFacade.nid(), procedure);
287364
}
288365

366+
/**
367+
* Applies the procedure to the latest version of each semantic of the given pattern
368+
* referencing the given component at this calculator's position — a
369+
* version-iteration operation: versions stamped in
370+
* {@link DefaultsTemplateTerm#DEFAULTS_AND_TEMPLATES_MODULE} are excluded, so
371+
* defaults/template semantics are never presented.
372+
*
373+
* @param componentNid the nid of the referenced component
374+
* @param patternNid the nid of the pattern whose semantics to iterate
375+
* @param procedure receives each latest semantic version with the component's and
376+
* pattern's latest versions
377+
*/
289378
void forEachSemanticVersionForComponentOfPattern(int componentNid, int patternNid, TriConsumer<SemanticEntityVersion, EntityVersion, PatternEntityVersion> procedure);
290379

291380
default void forEachSemanticVersionWithFieldsOfPattern(PatternFacade patternFacade,
@@ -337,7 +426,125 @@ default Latest<SemanticEntityVersion> latestSemanticVersion(SemanticEntity<?> se
337426
return (Latest<SemanticEntityVersion>) latest(semanticEntity);
338427
}
339428

429+
/**
430+
* Resolves the default value semantic of the given pattern at this calculator's
431+
* position: the semantic of {@code pattern} whose referenced component is
432+
* {@link DefaultsTemplateTerm#DEFAULT_VALUE_CONCEPT}, located by its computed
433+
* identity — {@link UuidT5Generator#singleSemanticUuid(PublicId, PublicId)} of the
434+
* pattern's public id and the defaults attachment concept's public id — never by
435+
* iteration.
436+
* <p>
437+
* Unlike the version-iteration operations, which exclude every version stamped in
438+
* {@link DefaultsTemplateTerm#DEFAULTS_AND_TEMPLATES_MODULE}, this accessor includes
439+
* that module. Resolution is the ordinary path calculus at the caller's position, so
440+
* preference is per-path: a default authored on the caller's path overrides one
441+
* inherited through the path's origins, and a retirement (an inactive version in the
442+
* same module) is honored with no resurrection of earlier active versions.
443+
*
444+
* @param pattern the pattern whose default value semantic to resolve
445+
* @return the latest version of the pattern's default value semantic at this
446+
* calculator's position; empty if none exists, none is reachable, or the
447+
* latest reachable version's state is not an allowed state
448+
*/
449+
default Latest<SemanticEntityVersion> getDefault(PatternFacade pattern) {
450+
return latest(defaultsSemanticNid(pattern, DefaultsTemplateTerm.DEFAULT_VALUE_CONCEPT));
451+
}
452+
453+
/**
454+
* Resolves the template semantic for the given purpose concept at this calculator's
455+
* position: the semantic whose referenced component is {@code purposeConcept} and
456+
* whose identity is the computed template identity
457+
* ({@link UuidT5Generator#singleSemanticUuid(PublicId, PublicId)} of its own
458+
* pattern's public id and the purpose concept's public id). Candidate semantics
459+
* attached to the purpose concept are enumerated at the chronology level (store
460+
* truth), and only the one carrying its computed identity is a template — other
461+
* attachments (descriptions, axioms) never match.
462+
* <p>
463+
* Unlike the version-iteration operations, which exclude every version stamped in
464+
* {@link DefaultsTemplateTerm#DEFAULTS_AND_TEMPLATES_MODULE}, this accessor includes
465+
* that module, and resolves per-path preference through the ordinary path calculus
466+
* at the caller's position.
467+
*
468+
* @param purposeConcept the template purpose concept — a child of
469+
* {@link DefaultsTemplateTerm#TEMPLATE_CONCEPT}
470+
* @return the latest version of the purpose's template semantic at this calculator's
471+
* position; empty if no template exists, none is reachable, or the latest
472+
* reachable version's state is not an allowed state
473+
* @throws IllegalStateException if more than one pattern declares a template for the
474+
* purpose concept — disambiguate with
475+
* {@link #getTemplate(PatternFacade, ConceptFacade)}
476+
*/
477+
default Latest<SemanticEntityVersion> getTemplate(ConceptFacade purposeConcept) {
478+
int templateNid = 0;
479+
for (int candidateNid : PrimitiveData.get().semanticNidsForComponent(purposeConcept.nid())) {
480+
EntityHandle handle = EntityHandle.get(candidateNid);
481+
if (!handle.isPresent() || !handle.isSemantic()) {
482+
continue;
483+
}
484+
SemanticEntity<?> candidate = handle.expectSemantic();
485+
UUID expectedIdentity = UuidT5Generator.singleSemanticUuid(
486+
PrimitiveData.publicId(candidate.patternNid()), purposeConcept.publicId());
487+
boolean identityMatches = false;
488+
for (UUID candidateUuid : candidate.publicId().asUuidArray()) {
489+
if (candidateUuid.equals(expectedIdentity)) {
490+
identityMatches = true;
491+
break;
492+
}
493+
}
494+
if (!identityMatches) {
495+
continue;
496+
}
497+
if (templateNid != 0) {
498+
throw new IllegalStateException(
499+
"More than one pattern declares a template for purpose " + purposeConcept
500+
+ " — resolve with getTemplate(pattern, purposeConcept)");
501+
}
502+
templateNid = candidateNid;
503+
}
504+
if (templateNid == 0) {
505+
return Latest.empty();
506+
}
507+
return latest(templateNid);
508+
}
509+
510+
/**
511+
* Resolves the template semantic of the given pattern for the given purpose concept
512+
* at this calculator's position, directly by computed identity —
513+
* {@link UuidT5Generator#singleSemanticUuid(PublicId, PublicId)} of the pattern's
514+
* public id and the purpose concept's public id. The pattern-free form
515+
* ({@link #getTemplate(ConceptFacade)}) resolves the same semantic by verifying
516+
* computed identity over the purpose concept's attachments; this form is exact when
517+
* the pattern is known.
518+
*
519+
* @param pattern the pattern whose template semantic to resolve
520+
* @param purposeConcept the template purpose concept — a child of
521+
* {@link DefaultsTemplateTerm#TEMPLATE_CONCEPT}
522+
* @return the latest version of the template semantic at this calculator's position;
523+
* empty if none exists, none is reachable, or the latest reachable version's
524+
* state is not an allowed state
525+
*/
526+
default Latest<SemanticEntityVersion> getTemplate(PatternFacade pattern, ConceptFacade purposeConcept) {
527+
return latest(defaultsSemanticNid(pattern, purposeConcept));
528+
}
340529

530+
/**
531+
* Computes the nid of a defaults/template semantic from its computed identity:
532+
* {@link UuidT5Generator#singleSemanticUuid(PublicId, PublicId)} of the pattern's
533+
* public id and the attachment concept's public id, minted pattern-scoped exactly as
534+
* the writing side mints it, so reader and writer resolve the same nid whether or
535+
* not the semantic exists yet.
536+
*
537+
* @param pattern the semantic's pattern
538+
* @param attachmentConcept the semantic's referenced component — the defaults
539+
* attachment concept, or a template purpose concept
540+
* @return the nid of the computed identity (minted if not yet present)
541+
*/
542+
private static int defaultsSemanticNid(PatternFacade pattern, EntityFacade attachmentConcept) {
543+
UUID semanticUuid = UuidT5Generator.singleSemanticUuid(
544+
pattern.publicId(), attachmentConcept.publicId());
545+
return ScopedValue.where(PrimitiveData.SCOPED_PATTERN_PUBLICID_FOR_NID, pattern.publicId())
546+
.call(() -> PrimitiveData.nid(semanticUuid));
547+
}
341548

342549
OptionalInt getIndexForMeaning(int patternNid, int meaningNid);
343550

0 commit comments

Comments
 (0)