Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions src/opendox/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,10 @@
# register the defaults where no host has. `is_rfc3339_datetime` is not a seam:
# it is the neutral contract's own date-time rule, and openDox owns it.
from opendox import projection_seams # noqa: E402
# openDox's own defaults for the two doxBench seams (plan 034 T085), which
# the entry points below register the same way. Importing it registers
# nothing.
from opendox import doxbench_defaults # noqa: E402
from opendox.rfc3339 import is_rfc3339_datetime # noqa: E402

# THE COMPOSITION POINT, BOUND AT LAST (§ 4.3; RULED ASK-2 option (2),
Expand Down Expand Up @@ -1113,6 +1117,10 @@ def build_parser(*, subcommand_extensions: tuple = ()) -> argparse.ArgumentParse
# only where no host has registered its own. Registering reads nothing, so
# a host that registers after this parser is built still replaces them.
projection_seams.register_defaults()
# AND openDox's OWN doxBench validators and status-exemption rail (4.3,
# T085; R1Q10 (a) and R1Q12 (a), the same pattern), each only where no
# host has registered its own, and replaceable by a host until read.
doxbench_defaults.register_defaults()
parser = argparse.ArgumentParser(prog="ideation-dashboard", description=__doc__,
formatter_class=argparse.RawDescriptionHelpFormatter)
sub = parser.add_subparsers(dest="command", required=True)
Expand Down Expand Up @@ -1220,6 +1228,8 @@ def main(argv: list[str] | None = None, *,
generator_seam.register_default(default_generator.GENERATOR)
# AND openDox's own projection defaults (5.5, T055), the same way.
projection_seams.register_defaults()
# AND openDox's own doxBench defaults (4.3, T085), the same way.
doxbench_defaults.register_defaults()
args = build_parser(
subcommand_extensions=subcommand_extensions).parse_args(argv)
try:
Expand Down
3 changes: 2 additions & 1 deletion src/opendox/contracts/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@
puts them on disk beside the validator and the assembly root remains their
source of truth for editing"*. So a code-leg checkout with no assembly root
around it still has them, and so does an install. `opendox.validator` reads
them from here, and T085's doxBench validators will read the same copies.
them from here, and so do its doxBench validators
(`opendox.validator.doxbench_validators`, the default T085 registers).

WHAT IS HERE.

Expand Down
97 changes: 12 additions & 85 deletions src/opendox/default_projection.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,14 +63,15 @@
is searched for, and no path can make the validator reachable or not. No
subprocess runs, so there is no dependency remedy (`dependency_remedy` is
None).
* THE WORKBENCH MANIFEST'S TWO VALIDATOR RULES. Its schema says of two rules
that it cannot state them, and leaves them to the validator. The consumer's
script checked them in single-file mode, and they are carried here, under
its identifiers, so routing `validate_manifest` to openDox's validator drops
neither (the holder's decision, 2026-09-28). `workbench-pinned-not-checked`:
every `recipe.pinned` keyword is also in `recipe.checked`.
`workbench-candidate-overlap`: no `recipe.new_candidates` document is
already a member or excluded.
* THE WORKBENCH MANIFEST'S TWO VALIDATOR RULES ARE THE VALIDATOR'S. Its
schema says of two rules that it cannot state them, and leaves them to the
validator. T058 carried them here, under the consumer script's
identifiers. Since plan 034's T085 (RULED `openxFactory#656` comment
`5920216845`, item 2, *"Move into openDox's validator (Recommended)"*),
`opendox.validator` owns them, as `pinned-keywords-are-checked` and
`new-candidates-are-disjoint`, and they reach this adapter's report
through `validator_for(kind).violations()` like every other rule of the
kind. This module checks neither.

IMPORT WEIGHT. `opendox.generator_seam`, `opendox.projection_seams` and the
standard library. So this module imports with no extra installed and no
Expand All @@ -97,7 +98,7 @@
from opendox import generator_seam, projection_seams

__all__ = ["CORPUS_ROOT", "CorpusRoot", "OWN_KINDS", "OwnValidator",
"NUMBER_RULE", "SYNTAX_RULE", "SnapshotNotWritable", "VALIDATORS", "WORKBENCH_RULES",
"NUMBER_RULE", "SYNTAX_RULE", "SnapshotNotWritable", "VALIDATORS",
"WRITER", "Writer"]

#: The workbench manifest's kind, `opendox.workbench.KIND`, restated because
Expand All @@ -110,7 +111,8 @@
#: generate verb writes with openDox's own generator, and the workbench
#: manifest `workbench.save()` validates. `opendox.validator` validates the
#: doxBench wire kinds too, and they reach it through their own seam
#: (`serve_wire.register_doxbench_validators`, T085), not through this one.
#: (`serve_wire`'s doxBench-validators seam, where the entry points register
#: `opendox.doxbench_defaults`'s default, T085), not through this one.
OWN_KINDS: tuple[str, ...] = (generator_seam.NEUTRAL_SNAPSHOT_KIND, WORKBENCH_KIND)

#: How each own kind is written, and so how its document is read.
Expand All @@ -129,11 +131,6 @@
#: (Copilot at openDox-code#68 c7768ed5, r4146428769).
NUMBER_RULE = "document-number"

#: The workbench manifest's two validator rules, which its schema leaves to
#: the validator, under the identifiers the consumer's script gave them.
WORKBENCH_RULES: tuple[str, ...] = ("workbench-pinned-not-checked",
"workbench-candidate-overlap")


class CorpusRoot:
"""openDox's own corpus-root predicate: a git repository's root."""
Expand Down Expand Up @@ -346,48 +343,6 @@ def _refuse_repeated_keys(pairs: list[tuple[str, Any]]) -> dict[str, Any]:
return document


def _names(value: Any) -> list[str]:
"""A list's string entries, once each, in order. Anything else answers
none: its shape is the schema's to judge, and these rules only compare.

Linear: the schema bounds none of the three lists, so membership is a
set's, and the list only keeps the order (Copilot at openDox-code#68
09cd1e8a, r4139734444)."""
if not isinstance(value, list):
return []
names: list[str] = []
seen: set[str] = set()
for item in value:
if isinstance(item, str) and item not in seen:
seen.add(item)
names.append(item)
return names


#: How many names a rule's detail quotes before it says how many more, and
#: how much of each name it quotes.
_QUOTED = 10
_NAME_CHARS = 80


def _quoted(names: list[str]) -> str:
"""`names` as a detail quotes them: the first few, each cut to a readable
length, and a count of the rest, so one violation stays one readable line.
The schema bounds neither the lists nor their strings (Copilot at
openDox-code#68 21e4723f, r4139769791)."""
shown = repr([name if len(name) <= _NAME_CHARS else name[:_NAME_CHARS - 1] + "…"
for name in names[:_QUOTED]])
return shown if len(names) <= _QUOTED else f"{shown[:-1]}, and {len(names) - _QUOTED} more]"


def _documents(entries: Any) -> set[str]:
"""The `document` of each entry of a members or excluded list."""
if not isinstance(entries, list):
return set()
return {entry["document"] for entry in entries
if isinstance(entry, dict) and isinstance(entry.get("document"), str)}


class OwnValidator:
"""openDox's own validator for ONE of its kinds, behind the validator
lookup's protocol (plan 034's T058; this module's docstring)."""
Expand Down Expand Up @@ -434,32 +389,6 @@ def construct_float(loader, node):
except yaml.YAMLError as exc:
raise ValueError(" ".join(str(exc).split())) from exc

@staticmethod
def _workbench_rules(document: Any) -> list:
"""The manifest's two validator rules (this module's docstring)."""
from opendox.validator import Violation

if not isinstance(document, dict) or not isinstance(document.get("recipe"), dict):
return []
recipe = document["recipe"]
found = []
checked = set(_names(recipe.get("checked")))
stray = [name for name in _names(recipe.get("pinned")) if name not in checked]
if stray:
found.append(Violation(
WORKBENCH_RULES[0], ("recipe", "pinned"), "workbench-rule",
f"pinned keyword(s) {_quoted(stray)} are not in checked: every pinned "
"keyword MUST also be checked"))
placed = _documents(document.get("members")) | _documents(document.get("excluded"))
overlap = [name for name in _names(recipe.get("new_candidates")) if name in placed]
if overlap:
found.append(Violation(
WORKBENCH_RULES[1], ("recipe", "new_candidates"), "workbench-rule",
f"new_candidates {_quoted(overlap)} already appear in members or "
"excluded: a new candidate is a document the set has not "
"placed yet"))
return found

def validate(self, path: Path | str, *, strict: bool = False,
search_from: tuple = ()) -> projection_seams.ValidationResult:
"""Validate the document at `path` as this validator's kind. `strict`
Expand Down Expand Up @@ -505,8 +434,6 @@ def validate(self, path: Path | str, *, strict: bool = False,
f"{' '.join(str(exc).split()) or type(exc).__name__}")]
else:
violations = kind_validator.violations(document)
if self.kind == WORKBENCH_KIND:
violations += self._workbench_rules(document)
if not violations:
return projection_seams.ValidationResult(
True, 0, f"{self.kind}: 0 violations, by {ran}\n", "", ran)
Expand Down
120 changes: 120 additions & 0 deletions src/opendox/doxbench_defaults.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
"""openDox's OWN defaults for the two doxBench seams: the schema validators and
the status-exemption rail (plan 034's T085; #1144's 4.3 as T007's batch G
amends it, and 16.4 in part; R1Q10 (a) and R1Q12 (a), `openxFactory#656`
comment `5850003126`).

WHY THIS FILE EXISTS. T027 made two of the eight reaches into openxFactory
seams: `serve_wire.py:1369`, which imported openxFactory's doxBench contract
validators, and `doxbench_packet.py:177`, which imported its `Status:` reader.
Each refuses, naming itself, when nothing is registered, and openxFactory
registers its own (T046). Standalone, nothing did, so the served model catalog
answered `catalog_unavailable` and no context packet could be assembled. Batch
G's addendum to 4.3 names the standalone defaults: *"openDox's default
validators run over its spec leg's two chat schemas,
`xfactory-workbench-chat-turn` and `xfactory-workbench-model-catalog`, and
there is no status exemption by default."* This module holds them.

THE ENTRY POINTS REGISTER THEM WHERE NO HOST HAS (R1Q3 (a), comment
`5817152735`). `cli.build_parser()`, `cli.main()`, `serve.build_server()` and
`serve.main()` call `register_defaults()`, beside their registrations of the
default profile, home corpus, generator and projection defaults. Each seam
keeps the projection seams' rules:

* a process that runs none of them still refuses, naming the seam and its
call (4.2's discipline). A default is a registration an entry point makes,
never a fallback inside a seam;
* a host's registration made before the default has been read replaces it;
* after the default has been read, a host's registration is refused (R1Q3
(ii); RN-1 (a)), so one process never verifies its model routes against two
factories, or marks its packets by two readers;
* the same registration again is a no-op.

THE TWO DEFAULTS.

* THE VALIDATORS: `opendox.validator.doxbench_validators`, openDox's own
validator over its packaged copies of the two doxBench schemas (T057,
R1Q12 (a)), one validator per wire kind. The seam calls it once per request,
and each call proves every copy against its recorded digest before it is
read, so a changed byte is refused on the request that reads it.
* THE RAIL: `NO_STATUS_EXEMPTION`. It marks NO source exempt from aggressive
compression, whatever its status says. openDox has no lifecycle vocabulary
of its own, and "exempt" is a word only such a vocabulary gives a status.
It still REPORTS a document's own `Status:` line, the raw value, as the
packet labels each source with it. Reporting none would label a document
that carries one as having "no Status: header", which would be false. It
reads the line the way openxFactory's reader does: the first `Status:` line
among the first `STATUS_SCAN_LINES` real lines, where only CR, LF and CRLF
end a line.

IMPORT WEIGHT. The standard library only. `register_defaults()` imports the
two seam modules and `opendox.validator` when it is CALLED, so importing this
module registers nothing and names no sibling.

A CREATED FILE: it has no row in openxFactory's
`docs/opendox-carve-manifest.yaml`, because the manifest declares what LEAVES
openxFactory and never what a destination assembles (RULED OQ-C).
"""

from __future__ import annotations

import re

__all__ = ["NO_STATUS_EXEMPTION", "NoStatusExemption", "register_defaults"]

#: The real line separators: CR, LF and CRLF, and nothing else, so an exotic
#: separator (a form feed, U+2028) cannot move a `Status:` line into the
#: window or out of it.
_REAL_LINE_END = re.compile(r"\r\n|\r|\n")


class NoStatusExemption:
"""openDox's own status-exemption rail: no source is exempt.

It carries `doxbench_packet.STATUS_EXEMPTION_REQUIRED`, and the two
constants a reader of the rail's names may ask for on
`opendox.doxbench_packet`."""

#: The statuses whose content is exempt from aggressive compression: none.
EXEMPT_STATUSES: frozenset[str] = frozenset()

#: How many of a document's first real lines are read for its `Status:`.
STATUS_SCAN_LINES = 15

_STATUS_RE = re.compile(r"^Status:\s*(.+?)\s*$")

Check warning on line 83 in src/opendox/doxbench_defaults.py

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Simplify this regular expression to reduce its runtime, as it has super-linear performance due to backtracking.

See more on https://sonarcloud.io/project/issues?id=opensoft_openDox-code&issues=AaD-Sb2_0s9IIvH8gokN&open=AaD-Sb2_0s9IIvH8gokN&pullRequest=71

def lifecycle_status(self, text: str) -> str | None:
"""The document's own declared `Status:`, raw, or None when it
declares none in its first `STATUS_SCAN_LINES` real lines."""
if not isinstance(text, str):
return None
for line in _REAL_LINE_END.split(text)[:self.STATUS_SCAN_LINES]:
match = self._STATUS_RE.match(line)
if match:
return match.group(1)
return None

def is_compression_exempt(self, text: str) -> bool:

Check warning on line 96 in src/opendox/doxbench_defaults.py

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Remove the unused function parameter "text".

See more on https://sonarcloud.io/project/issues?id=opensoft_openDox-code&issues=AaD-Sb2_0s9IIvH8gokO&open=AaD-Sb2_0s9IIvH8gokO&pullRequest=71
"""Never: there is no status exemption by default (batch G's addendum
to #1144's 4.3)."""
return False

def __repr__(self) -> str:
return "<openDox's own status-exemption rail: no exemption>"


#: The one rail an entry point registers.
NO_STATUS_EXEMPTION = NoStatusExemption()


def register_defaults() -> None:
"""Register openDox's OWN default at each of the two doxBench seams, where
no host has registered one (R1Q10 (a), in R1Q3 (a)'s pattern).

The entry points call this beside their other default registrations. It
registers nothing over a host, and reads nothing, so a host registration
made afterwards, and before any request reads a default, still replaces
it. Importing this module registers nothing."""
from opendox import doxbench_packet, serve_wire, validator

serve_wire.register_default_doxbench_validators(validator.doxbench_validators)
doxbench_packet.register_default_status_exemption(NO_STATUS_EXEMPTION)
Loading
Loading