feat(profiles): SEGMENTED_V1 profile and SegmentationPolicy capability
This commit is contained in:
parent
499253e53b
commit
cd2c7517b0
3 changed files with 190 additions and 0 deletions
|
|
@ -758,6 +758,37 @@ class IndexPolicy:
|
|||
return found
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class SegmentationPolicy:
|
||||
"""Whether a bundle admits one document expanding into many concepts.
|
||||
|
||||
OKF v0.2 §2 calls a concept "a single unit of knowledge within a bundle"
|
||||
and a concept ID "the path of the concept's file within the bundle" —
|
||||
neither ties a concept to a source file. A door emitting exactly one flat
|
||||
concept per dropped file therefore implements the shape Appendix A
|
||||
presents v0.2 as migrating AWAY from, and §11 cannot notice: it checks
|
||||
that every non-reserved `.md` parses with a non-empty `type`, so one giant
|
||||
concept is fully conformant. Conformance is the floor, not the proof.
|
||||
|
||||
The presence of this object IS the capability. Every downstream branch
|
||||
reads `profile.segmentation is not None` and never
|
||||
`IndexPolicy.per_directory`: `STRICT_V1` already sets that field True
|
||||
while Door B ignores it, so keying the 1-to-N path there would silently
|
||||
change a shipped profile's output and break its byte-stability pin.
|
||||
|
||||
Every field NAMES a key and none supplies a value. The value of
|
||||
`bundle_id` tracks the caller's own identity scheme, so it arrives through
|
||||
`root_frontmatter_values` (decision D5): a constant here would claim a
|
||||
decision this library does not own.
|
||||
"""
|
||||
|
||||
hierarchical_paths: bool = True
|
||||
bundle_id_key: str = "bundle_id"
|
||||
segment_id_key: str = "segment_id"
|
||||
offset_key: str = "source_offset"
|
||||
nav_label: str = "index"
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class BundleProfile:
|
||||
"""One bundle contract: types, frontmatter, filenames, index."""
|
||||
|
|
@ -767,6 +798,11 @@ class BundleProfile:
|
|||
paths: PathPolicy
|
||||
index: IndexPolicy
|
||||
ownership: OwnershipPolicy = field(default_factory=OwnershipPolicy)
|
||||
# Defaulted, so all four existing constants construct unchanged and every
|
||||
# positional call site stays source-compatible. `None` is not "segmentation
|
||||
# off" as a setting — it is the profile not having the capability at all,
|
||||
# which is what the downstream `is not None` checks read.
|
||||
segmentation: SegmentationPolicy | None = None
|
||||
|
||||
|
||||
# The ingest-spec + Phase 2 contract. Every value here was a constant in
|
||||
|
|
@ -1039,6 +1075,41 @@ OKF_V0_2 = BundleProfile(
|
|||
)
|
||||
|
||||
|
||||
# STRUCTURED_V1 plus the capability to split ONE document into MANY concepts.
|
||||
#
|
||||
# A new profile rather than a flag on an existing one, for the same reason
|
||||
# STRUCTURED_V1 was: `DEFAULT` states commons' ingest-spec §6 layer and
|
||||
# `STRICT_V1` mirrors a consumer's ratified contract, so moving either one's
|
||||
# bytes from here would be this repo editing another repo's contract (O2).
|
||||
# `OKF_V0_2` states upstream's. What stays byte-stable is therefore all four of
|
||||
# them, proven by `tests/test_segmented_profile.py` at the profile level and by
|
||||
# the golden suite at the byte level.
|
||||
#
|
||||
# What this profile adds on top of STRUCTURED_V1's facets and structure keys:
|
||||
#
|
||||
# - `segmentation` — the capability itself. Its presence is what every 1-to-N
|
||||
# branch keys on.
|
||||
# - `per_directory` — a segmented bundle has directories, and a bundle whose
|
||||
# nested concepts are reachable only by guessing a path is a filing cabinet
|
||||
# again. Set HERE rather than inherited, because STRUCTURED_V1 leaves it off.
|
||||
# - `root_frontmatter=("bundle_id",)` — the identity carrier settled by order
|
||||
# `…2527032751`: form (c), a root identifier consumers join on. Naming the
|
||||
# key PERMITS it and fixes its position; the caller supplies the value (D5),
|
||||
# because a bundle is a collection the caller delimits and only the caller
|
||||
# knows what it is called. It is deliberately absent from
|
||||
# `root_frontmatter_required`: Door B refuses a segmentation plan without an
|
||||
# id, which is a rule about the door, not about every index this profile
|
||||
# might ever write.
|
||||
SEGMENTED_V1 = BundleProfile(
|
||||
types=STRUCTURED_V1.types,
|
||||
frontmatter=STRUCTURED_V1.frontmatter,
|
||||
paths=STRUCTURED_V1.paths,
|
||||
index=replace(STRUCTURED_V1.index, per_directory=True, root_frontmatter=("bundle_id",)),
|
||||
ownership=STRUCTURED_V1.ownership,
|
||||
segmentation=SegmentationPolicy(),
|
||||
)
|
||||
|
||||
|
||||
# "The latest version supported as STABLE", not the latest present in this
|
||||
# module. It therefore keeps v0.1 UPSTREAM semantics for as long as v0.2 is
|
||||
# provisional, and flipping it is the GA event — one auditable action rather
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue