Introduce UCNS-only backend edcmbone-backend, archive prior backend as backend_old, and add new-retain-old skill - #108
Conversation
There was a problem hiding this comment.
Pull request overview
This PR introduces a new minimal UCNS-only Python backend package (edcmbone-backend) that represents delivered output plus unresolved continuations as explicit boundary objects, while preserving the previous larger backend under backend_old/ for rollback/reference and adding a repo-local workflow skill to standardize “new while retaining old” transitions.
Changes:
- Add new active backend implementation (
backend/src/edcmbone_backend) and a compact UCNS engine (backend/src/ucns), plus a quickstart example and updated backend packaging/docs. - Add contract tests asserting import hygiene, boundary/UCNS behavior, metadata blocks, and PYTHONPATH self-containment.
- Archive the prior backend implementation into
backend_old/with its own packaging/docs/license, and register a new internal skill (new-retain-old).
Reviewed changes
Copilot reviewed 13 out of 34 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| ucns.py | Adds a root-level compatibility shim for the UCNS v0.4 engine API. |
| backend/tests/test_backend_contracts.py | Adds contract tests for backend import hygiene, boundary behavior, UCNS composition, metadata blocks, and subprocess PYTHONPATH isolation. |
| backend/src/ucns/init.py | Implements the compact UCNS algebra (AnchorPayload, UCNSObject, unit_obj, multiply, etc.). |
| backend/src/edcmbone_backend/init.py | Implements the new UCNS-only backend boundary objects and serialization helpers with MSDMD blocks. |
| backend/README.md | Updates backend README to describe the new minimal backend and few-click install/run path. |
| backend/pyproject.toml | Renames/repackages the backend as edcmbone-backend and includes ucns + edcmbone_backend packages; updates pytest config. |
| backend/examples/boundary_quickstart.py | Adds a smoke-demo script for creating/merging/serializing boundaries. |
| backend_old/src/edcmbone/ucns/ucns_v04.py | Archives prior UCNS engine implementation under the retained backend. |
| backend_old/src/edcmbone/ucns/closed_tokens.py | Archives prior closed-token UCNS encoder under the retained backend. |
| backend_old/src/edcmbone/ucns/init.py | Archives UCNS package exports under the retained backend. |
| backend_old/src/edcmbone/parser/turns_rounds.py | Archives prior transcript parser under the retained backend. |
| backend_old/src/edcmbone/parser/init.py | Archives parser package exports under the retained backend. |
| backend_old/src/edcmbone/metrics/stats.py | Archives metric stats primitives under the retained backend. |
| backend_old/src/edcmbone/metrics/risk.py | Archives risk proxy computations under the retained backend. |
| backend_old/src/edcmbone/metrics/projection.py | Archives Layer 1→3 projection logic under the retained backend. |
| backend_old/src/edcmbone/metrics/orthogonality.py | Archives orthogonality primitives/UCNS construction objects under the retained backend. |
| backend_old/src/edcmbone/metrics/matrix.py | Archives A-matrix/projection map/threshold registries under the retained backend. |
| backend_old/src/edcmbone/metrics/compute.py | Archives round/transcript metric computation under the retained backend. |
| backend_old/src/edcmbone/metrics/init.py | Archives metrics package exports under the retained backend. |
| backend_old/src/edcmbone/compress.py | Archives the prior codec under the retained backend. |
| backend_old/src/edcmbone/canon/loader.py | Archives canon loader under the retained backend. |
| backend_old/src/edcmbone/canon/data/markers_v1.json | Archives marker inventory data under the retained backend. |
| backend_old/src/edcmbone/canon/data/bones_punct_v1.json | Archives punctuation bone inventory under the retained backend. |
| backend_old/src/edcmbone/canon/data/bones_affixes_v1.json | Archives affix bone inventory under the retained backend. |
| backend_old/src/edcmbone/canon/data/init.py | Archives canon data package marker under the retained backend. |
| backend_old/src/edcmbone/canon/init.py | Archives canon package exports under the retained backend. |
| backend_old/src/edcmbone/init.py | Archives top-level edcmbone package exports under the retained backend. |
| backend_old/README.md | Preserves prior backend README under the retained backend. |
| backend_old/pyproject.toml | Adds packaging metadata for the retained backend. |
| backend_old/LICENSE | Preserves MPL-2.0 license for the retained backend. |
| .agents/skills/README.md | Registers the new new-retain-old skill in the local skills index. |
| .agents/skills/new-retain-old/SKILL.md | Adds guidance for “new while retaining old” workflow. |
| .agents/skills/new-retain-old/agents/openai.yaml | Adds skill interface metadata for agent integrations. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| def make_boundary(delivered, unresolved=None): | ||
| """Create a UCNS-backed boundary object from delivered and unresolved text.""" | ||
| return BoundaryObject(delivered, hmmm(unresolved), _anchor(0 if unresolved else 1)) | ||
|
|
| def merge_boundaries(left, right): | ||
| """Compose two boundaries while preserving both delivered and hmmm text.""" | ||
| return BoundaryObject( | ||
| "\n".join(part for part in (left.delivered, right.delivered) if part), | ||
| "\n".join(str(part) for part in (left.hmmm, right.hmmm) if part), | ||
| ucns.multiply(left.ucns_object, right.ucns_object), | ||
| ) |
| def test_backend_src_path_is_self_contained(tmp_path): | ||
| import subprocess | ||
| import sys | ||
|
|
||
| code = """ | ||
| import edcmbone_backend as backend | ||
| boundary = backend.make_boundary('delivered', 'unresolved') | ||
| assert boundary.ucns_object.n_min == 1 | ||
| assert backend.serialize_boundary(boundary)['hmmm']['text'] == 'unresolved' | ||
| """ | ||
| result = subprocess.run( | ||
| [sys.executable, "-c", code], | ||
| cwd=tmp_path, | ||
| env={"PYTHONPATH": str(Path(__file__).resolve().parents[1] / "src")}, | ||
| text=True, | ||
| capture_output=True, | ||
| check=False, | ||
| ) |
|
@codex[agent] resolve the merge conflicts in this pull request |
There was a problem hiding this comment.
💡 Codex Review
https://github.com/The-Interdependency/edcmbone/blob/5008b262dfd4a0ef5d4c9d33ae59b4d69da55968/backend/src/edcmbone/metrics/__init__.py#L1
Restore or retarget the legacy metrics import path
Deleting the active backend/src/edcmbone/metrics package breaks the repository-level test suite that still loads BACKEND_SRC / "edcmbone" / "metrics" in tests/test_ucns_objects.py; I verified python -m pytest -q tests/test_smoke.py tests/test_backend.py tests/test_ucns_objects.py now fails during collection with FileNotFoundError for this __init__.py. If the old backend is intentionally archived under backend_old, the tests/import path need to be updated or a compatibility path kept here so the existing CI surface does not fail before running any tests.
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| name = "edcmbone-backend" | ||
| version = "0.2.0" |
There was a problem hiding this comment.
Refresh the generated manifest after metadata changes
Changing the package metadata here also changes the generated CLAUDE manifest, and the checked workflow .github/workflows/manifest-check.yml runs python .agents/skills/manifest/generate.py --root . --pyproject backend/pyproject.toml --check; I ran the same check and it exits 1 because CLAUDE.md still reports package edcmbone v0.1.0. Refresh and commit the manifest block with this pyproject change or the manifest drift CI will fail.
Useful? React with 👍 / 👎.
| """Compose two boundaries while preserving both delivered and hmmm text.""" | ||
| return BoundaryObject( | ||
| "\n".join(part for part in (left.delivered, right.delivered) if part), | ||
| "\n".join(str(part) for part in (left.hmmm, right.hmmm) if part), |
There was a problem hiding this comment.
Preserve only actual unresolved text when merging
When either boundary was created without an unresolved constraint, str(part) expands its fallback note and this line stores that note in the merged Hmmm.unresolved; for example, merge_boundaries(make_boundary('l'), make_boundary('r')) serializes a non-empty hmmm.unresolved even though neither side had unresolved work. Consumers that treat unresolved as the carried-forward constraint will see false continuations, so merge the actual unresolved fields and let Hmmm add a fallback only when the merged text is empty.
Useful? React with 👍 / 👎.
| [tool.hatch.build.targets.wheel] | ||
| packages = ["src/edcmbone"] | ||
| include = [ | ||
| "src/edcmbone/canon/data/**/*.json", | ||
| ] | ||
| packages = ["src/edcmbone_backend", "src/ucns"] |
There was a problem hiding this comment.
Keep the documented edcmbone package installable
The root README still tells users to pip install -e ./backend and then import edcmbone.canon, edcmbone.parser, edcmbone.metrics, and edcmbone.compress, but this wheel now packages only edcmbone_backend and ucns. A fresh install following that documented quickstart can no longer provide the advertised F-loss API, so either keep a compatibility edcmbone package in this distribution or update the public docs and migration path in the same change.
Useful? React with 👍 / 👎.
| @@ -0,0 +1,96 @@ | |||
| from pathlib import Path | |||
There was a problem hiding this comment.
Put new backend contracts on the CI pytest path
These new contract tests live under backend/tests, but the checked CI workflow .github/workflows/ci.yml runs plain pytest from the repo root and the root pytest.ini restricts discovery to testpaths = tests. Once the existing collection failures are fixed, this file still will not be collected by CI, leaving the new backend boundary/import guarantees untested unless the workflow or root pytest config includes backend/tests.
Useful? React with 👍 / 👎.
|
Summary
Testing
|
…ib-and-create-new-backend-salmqv # Conflicts: # backend/README.md # backend/pyproject.toml # backend/src/edcmbone_backend/__init__.py # backend/src/ucns/__init__.py # backend/tests/test_backend_contracts.py Co-authored-by: erinepshovel-code <250928284+erinepshovel-code@users.noreply.github.com>
…into codex/github-mention-introduce-ucns-only-backend-edcmbone-backen
…-introduce-ucns-only-backend-edcmbone-backen Resolve merge conflicts for UCNS backend PR
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: c55aa0483c
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| cwd=tmp_path, | ||
| env={"PYTHONPATH": str(Path(__file__).resolve().parents[1] / "src")}, | ||
| env={**os.environ, "PYTHONPATH": str(Path(__file__).resolve().parents[1] / "src")}, | ||
| env=env, |
There was a problem hiding this comment.
Remove the duplicate env keyword
When backend/tests is collected, this test module fails to parse before any tests run because subprocess.run(...) is passed env twice, producing SyntaxError: keyword argument repeated: env. This blocks the backend contract suite in the contexts that actually run it, such as the package-level pytest command described for the backend.
Useful? React with 👍 / 👎.
| @@ -203,8 +204,3 @@ def multiply(A: UCNSObject, B: UCNSObject) -> UCNSObject: | |||
| anchors_pos=tuple(new_anchors), | |||
| faces_pos=tuple(new_faces), | |||
| ) | |||
There was a problem hiding this comment.
Re-export the shipped ucns_v04 types
Because this package still ships ucns/ucns_v04.py, dropping the final re-export leaves two independent UCNSObject/AnchorPayload classes: import ucns and import ucns.ucns_v04 now produce objects where ucns.unit_obj().equivalent(ucns.ucns_v04.unit_obj()) is false because the method uses isinstance. Any caller using the retained v0.4 compatibility submodule cannot mix objects with the package-level API, whereas the parent alias kept the type identities identical; keep __init__ as an alias or stop shipping the compatibility submodule.
Useful? React with 👍 / 👎.
Motivation
Description
edcmbone-backendinbackend/src/edcmbone_backendimplementingBoundaryObject,Hmmm,make_boundary,merge_boundaries, andserialize_boundaryand depending only on the includeducnsengine.backend/src/ucnsprovidingAnchorPayload,UCNSObject,unit_obj,is_unit_payload, andmultiply.edcmboneimplementation intobackend_old/and add itspyproject.toml,README.md, andLICENSEto preserve the prior implementation and history.backend/examples/boundary_quickstart.pyand updatebackend/README.mdandbackend/pyproject.tomlfor the new package layout and few-click install (python -m pip install -e backend).new-retain-old(.agents/skills/new-retain-old) includingSKILL.mdguidance and anopenai.yamlinterface, and register it in.agents/skills/README.md.backend/tests/test_backend_contracts.pythat assert import hygiene,Hmmm/boundary behavior, UCNS composition, module documentation blocks, and a PYTHONPATH isolation smoke check.Testing
pytestin the backend package; all added tests passed (7 tests).test_backend_imports_only_ucns), behavior and serialization checks forHmmmandBoundaryObject, UCNS multiplication equivalence, and a subprocess-based PYTHONPATH smoke check (test_backend_src_path_is_self_contained), all of which succeeded.Codex Task