feat(contracts): land New Hope + Slash Topics semantic-BI integration - #1129
Conversation
Import slash-topics as a first-class pinned contract (parity with new-hope / memory-mesh / semantic-serdes) and land the New Hope x Slash Topics integration pack into the platform: - contracts/imported/slash-topics/: SOURCE_MANIFEST (pinned 9037a91) + mirrored schema subset (SlashTopics pack, MembraneDecision v0.1/v0.2, Model Selection) - IMPORT_MANIFEST + validate_repo.py: declare AND enforce the slash-topics import - docs/INTEGRATION_NewHope_SlashTopics_SemanticBI.md + contracts/CANONICAL_SOURCES - examples/newhope-slash-topics/: the 4 vertical-slice fixtures - tools/validate_newhope_slashtopics_integration.py + test + CI workflow: a self-contained gate (schema invariants + fixtures validate against the mirror) Closes the gap where slash-topics was referenced by the integration but never imported. Validator, tests, and repo-wide validate_repo.py all green locally.
There was a problem hiding this comment.
Pull request overview
Note
Copilot couldn't run its full agentic review because it didn't start before the timeout. Make sure your repository has a runner available, or add a copilot-code-review.yml file specifying one with the runs-on attribute. See the docs for more details.
Adds the missing slash-topics imported contract and lands a self-contained CI validator to enforce the New Hope × Slash Topics × Semantic BI integration invariants.
Changes:
- Adds
slash-topicsas a pinned imported contract (manifest + mirrored spec subset) and enforces its presence via repo validation. - Introduces a dedicated validator script + pytest coverage, and wires it into a new GitHub Actions workflow.
- Adds integration docs and example fixtures to validate against mirrored schemas.
Reviewed changes
Copilot reviewed 16 out of 16 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| tools/validate_repo.py | Enforces presence of the new slash-topics imported source manifest. |
| tools/validate_newhope_slashtopics_integration.py | New integration validator (junk scan, provenance checks, invariants, fixture validation). |
| tools/tests/test_validate_newhope_slashtopics_integration.py | Adds tests to ensure the integration validator passes and required assets exist. |
| examples/newhope-slash-topics/slash_topics_pack_min.example.json | Adds minimal Slash Topics pack fixture. |
| examples/newhope-slash-topics/newhope_message_posted.example.json | Adds New Hope carrier fixture for the vertical slice. |
| examples/newhope-slash-topics/membrane_decision_allow.example.json | Adds MembraneDecision example fixture. |
| examples/newhope-slash-topics/embedding_receipt_lsi.example.json | Adds embedding receipt fixture for the vertical slice. |
| docs/INTEGRATION_NewHope_SlashTopics_SemanticBI.md | Documents the integration mapping, event flow, and safety posture. |
| contracts/imported/slash-topics/specs/SlashTopics_Schema_v0.1.json | Mirrors Slash Topics pack schema subset into the repo. |
| contracts/imported/slash-topics/specs/Model_Selection_Policy_v0.1.json | Mirrors model-selection policy artifact into the repo. |
| contracts/imported/slash-topics/specs/Membrane_Decision_v0.2.json | Mirrors MembraneDecision v0.2 schema into the repo. |
| contracts/imported/slash-topics/specs/Membrane_Decision_v0.1.json | Mirrors MembraneDecision v0.1 schema into the repo. |
| contracts/imported/slash-topics/SOURCE_MANIFEST.yaml | Declares provenance/pin and mirrored objects for slash-topics. |
| contracts/imported/IMPORT_MANIFEST.yaml | Registers slash-topics import entry and validation hooks. |
| contracts/imported/CANONICAL_SOURCES.yaml | Adds canonical source registry defining ownership/mirroring rules. |
| .github/workflows/newhope-slashtopics-integration.yml | Adds CI workflow to run the integration validator and its tests. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| manifest = yaml.safe_load(IMPORT_MANIFEST.read_text(encoding="utf-8")) | ||
| by_repo = {i.get("repo"): i for i in manifest.get("imports", [])} | ||
| for repo in ("SocioProphet/new-hope", "SocioProphet/slash-topics"): | ||
| entry = by_repo.get(repo) | ||
| if not entry: | ||
| fail(f"IMPORT_MANIFEST does not declare {repo}") | ||
| if not entry.get("pin"): | ||
| fail(f"IMPORT_MANIFEST entry for {repo} has no pin (provenance required)") |
| Draft202012Validator(schema).validate(pack_example) | ||
| Draft202012Validator(md_schema).validate(md_example) | ||
| ok("Landed example fixtures validate against the mirrored Slash Topics schemas") |
| pack_example = load_json(EXAMPLES / "slash_topics_pack_min.example.json") | ||
| md_example = load_json(EXAMPLES / "membrane_decision_allow.example.json") | ||
|
|
||
| Draft202012Validator(schema).validate(pack_example) | ||
| Draft202012Validator(md_schema).validate(md_example) |
| - name: Install validator dependencies | ||
| run: pip install jsonschema pyyaml pytest |
| def fail(msg: str) -> None: | ||
| print(f"[FAIL] {msg}", file=sys.stderr) | ||
| sys.exit(1) |
…I deps (Copilot review #1129) - assert_import_provenance: try/except on read/parse + validate YAML shape before use - validate_examples: catch jsonschema ValidationError -> controlled [FAIL]; parse-check all 4 landed fixtures (schema-validate the 2 with mirrored slash-topics schemas) - CI: pin jsonschema/PyYAML/pytest for reproducible runs
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 16 out of 16 changed files in this pull request and generated 1 comment.
Comments suppressed due to low confidence (3)
tools/validate_newhope_slashtopics_integration.py:35
- The junk-artifact scan will not cover the
docs/directory because the docs entry inLANDED_PATHSis a file and the scan only runs for directories (if base.is_dir()). This means.DS_Store(or__MACOSX) underdocs/could slip through even though the docstring claims it checks all landed integration paths. Consider changing the docs entry toROOT / \"docs\"(or...md.parent) or extending the logic to scanbase.parentwhenbaseis a file.
LANDED_PATHS = [SLASH, EXAMPLES, ROOT / "docs" / "INTEGRATION_NewHope_SlashTopics_SemanticBI.md"]
tools/validate_newhope_slashtopics_integration.py:62
- The junk-artifact scan will not cover the
docs/directory because the docs entry inLANDED_PATHSis a file and the scan only runs for directories (if base.is_dir()). This means.DS_Store(or__MACOSX) underdocs/could slip through even though the docstring claims it checks all landed integration paths. Consider changing the docs entry toROOT / \"docs\"(or...md.parent) or extending the logic to scanbase.parentwhenbaseis a file.
for base in LANDED_PATHS:
if base.is_dir():
for p in base.rglob("*"):
if p.name == ".DS_Store" or "__MACOSX" in p.parts:
junk.append(str(p.relative_to(ROOT)))
.github/workflows/newhope-slashtopics-integration.yml:49
- The workflow pins Python packages but leaves
python-versionas3.x, which can introduce breakage when GitHub Actions advances the default 3.x minor (and can undermine the stated reproducibility goal). Consider pinning a specific minor (e.g.,3.11/3.12) to make CI behavior stable over time.
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.x'
- name: Install validator dependencies (pinned for reproducibility)
run: pip install jsonschema==4.23.0 PyYAML==6.0.2 pytest==8.3.4
| local_path: contracts/imported/slash-topics/ | ||
| required_objects: | ||
| - SlashTopics_Schema_v0.1.json | ||
| - Membrane_Decision_v0.1.json | ||
| - Membrane_Decision_v0.2.json | ||
| - Model_Selection_Policy_v0.1.json |
…rce them (Copilot #1129) - IMPORT_MANIFEST required_objects now list the real specs/ paths (were bare basenames; would not resolve relative to local_path) - validator now asserts each slash-topics required_object exists under local_path (declared AND enforced)
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 16 out of 16 changed files in this pull request and generated 1 comment.
Comments suppressed due to low confidence (5)
tools/validate_newhope_slashtopics_integration.py:77
- If
required_objectsis present but not a list (e.g., a string), the loop will iterate unexpected values (characters) and the validator may fail in confusing ways; similarly, a non-stringlocal_pathcan throw aTypeErrorduring path joining. Add explicit type checks (e.g.,local_pathis a non-empty string;required_objectsis a list of strings) and callfail(...)with a clear message when malformed.
if not isinstance(manifest, dict) or not isinstance(manifest.get("imports"), list):
fail("IMPORT_MANIFEST malformed: expected a mapping with an 'imports' list")
by_repo = {i.get("repo"): i for i in manifest["imports"] if isinstance(i, dict)}
tools/validate_newhope_slashtopics_integration.py:89
- If
required_objectsis present but not a list (e.g., a string), the loop will iterate unexpected values (characters) and the validator may fail in confusing ways; similarly, a non-stringlocal_pathcan throw aTypeErrorduring path joining. Add explicit type checks (e.g.,local_pathis a non-empty string;required_objectsis a list of strings) and callfail(...)with a clear message when malformed.
local_path = ROOT / st.get("local_path", "contracts/imported/slash-topics/")
for obj in st.get("required_objects", []):
tools/validate_newhope_slashtopics_integration.py:35
- The junk-file scan only recurses into directories; since the docs entry is a file path, junk under
docs/(e.g.,docs/.DS_Store) will not be detected even though docs are part of the landed integration. Consider scanningROOT / \"docs\"(orPath(...).parent) instead of the single markdown file so the check matches the stated intent.
LANDED_PATHS = [SLASH, EXAMPLES, ROOT / "docs" / "INTEGRATION_NewHope_SlashTopics_SemanticBI.md"]
tools/validate_newhope_slashtopics_integration.py:61
- The junk-file scan only recurses into directories; since the docs entry is a file path, junk under
docs/(e.g.,docs/.DS_Store) will not be detected even though docs are part of the landed integration. Consider scanningROOT / \"docs\"(orPath(...).parent) instead of the single markdown file so the check matches the stated intent.
for base in LANDED_PATHS:
if base.is_dir():
for p in base.rglob("*"):
if p.name == ".DS_Store" or "__MACOSX" in p.parts:
contracts/imported/slash-topics/specs/Membrane_Decision_v0.1.json:3
- Unlike
Membrane_Decision_v0.2.json, the v0.1 schema is missing a$id. Adding a stable$idimproves schema tooling/interoperability (especially if any downstream validator/resolver relies on schema identifiers) and keeps the mirrored schema set consistent.
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"properties": {
|
|
||
| def assert_schema_invariants() -> None: | ||
| schema = load_json(SPECS / "SlashTopics_Schema_v0.1.json") | ||
| md = load_json(SPECS / "Membrane_Decision_v0.1.json") | ||
| model = load_json(SPECS / "Model_Selection_Policy_v0.1.json") | ||
|
|
||
| required = set(schema.get("required", [])) |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 16 out of 16 changed files in this pull request and generated 1 comment.
Comments suppressed due to low confidence (3)
tools/validate_newhope_slashtopics_integration.py:40
- Repo validators appear to already have a
fail()helper with consistent formatting and exit semantics (context excerpt showsraise SystemExit(2)andERR:prefix). This script redefinesfail()with different output format and exit code, which can make CI behavior and log parsing inconsistent across validators. Prefer reusing the shared helper (or matching its exit code + message format) so failures are uniform.
def fail(msg: str) -> None:
print(f"[FAIL] {msg}", file=sys.stderr)
sys.exit(1)
.github/workflows/newhope-slashtopics-integration.yml:49
- The workflow pins library versions 'for reproducibility' but uses
python-version: '3.x', which can change interpreter minor versions over time and break reproducibility (and possibly dependency resolution). Pin a specific Python version (e.g.,3.11/3.12) to align with the reproducibility goal, or relax dependency pins if you want broader interpreter compatibility. Also consider invoking pip aspython -m pip ...to ensure the pip bound to the configured interpreter is used.
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.x'
- name: Install validator dependencies (pinned for reproducibility)
run: pip install jsonschema==4.23.0 PyYAML==6.0.2 pytest==8.3.4
tools/validate_newhope_slashtopics_integration.py:53
- Error output includes an absolute filesystem path (
{path}), while other failures sometimes userelative_to(ROOT). For CI logs and portability (and to avoid leaking runner filesystem structure), prefer normalizing paths topath.relative_to(ROOT)when possible, and fall back to the original string only if it cannot be relativized.
except Exception as e: # noqa: BLE001
fail(f"Could not parse JSON: {path} ({e})")
| # Enforce slash-topics required_objects: each must resolve under its local_path. | ||
| st = by_repo["SocioProphet/slash-topics"] | ||
| local_path = ROOT / st.get("local_path", "contracts/imported/slash-topics/") | ||
| for obj in st.get("required_objects", []): | ||
| if not (local_path / obj).is_file(): | ||
| fail(f"slash-topics required_object not mirrored: {(local_path / obj)}") |
What & why
Lands the New Hope × Slash Topics × Semantic BI integration into the platform and closes a real gap:
slash-topicswas referenced by the integration but never imported (new-hope, memory-mesh, semantic-serdes were). Sourced from thenewhope-slash-topics-integrationpack that previously lived only on a local machine (no remote).Changes
contracts/imported/slash-topics/SOURCE_MANIFEST.yaml(pinned to9037a91) + mirrored schema subset (SlashTopics pack v0.1, MembraneDecision v0.1/v0.2, Model Selection policy v0.1), parity with the existing imports.IMPORT_MANIFEST.yamland tovalidate_repo.py's required-manifest gate.docs/INTEGRATION_NewHope_SlashTopics_SemanticBI.md+contracts/imported/CANONICAL_SOURCES.yaml(single-source-of-truth registry).examples/newhope-slash-topics/(the 4 vertical-slice examples).tools/validate_newhope_slashtopics_integration.py(+ test) validates junk-freeness, import provenance/pins, schema invariants (MembraneDecision enum, encoder-disabled-by-default posture), and that fixtures validate against the mirrored schemas. Wired via.github/workflows/newhope-slashtopics-integration.yml.Verification (local)
validate_newhope_slashtopics_integration.py→ all 6 checks pass (rc=0)pytest tools/tests/test_validate_newhope_slashtopics_integration.py→ 2 passedtools/validate_repo.py(umbrella) →OK: validate passedFollow-on (not in this PR)
Standing up the runtime services for the event flow (Membrane → TopicProjection → Vectorization → Semantic BI lens). Adapters already exist (
apps/knowledge-reason/service/new_hope_adapter.py,newHopeMembrane.ts,slashTopicsScope.ts); this PR lands the contracts they bind to.