Skip to content
This repository was archived by the owner on Jul 29, 2026. It is now read-only.
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
1 change: 1 addition & 0 deletions .agents/skills/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ Installed skills:
- `msdmd/` — Module Self-Declared Metadata Markdown
- `test-build/` — test contract metadata blocks
- `meta-module-build/` — metadata-first module scaffolding
- `new-retain-old/` — safe replacement workflow that preserves the old implementation while creating a new active path
- `manifest/` — living-spec generator for `CLAUDE.md` (vendored from
`The-Interdependency/skill-lib@d6e4d78`). Generates the mechanical facts
block in `CLAUDE.md` from `backend/pyproject.toml` + the tree; the
Expand Down
96 changes: 96 additions & 0 deletions .agents/skills/new-retain-old/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
---
name: new-retain-old
description: Preserve the prior implementation while creating a replacement implementation with explicit rollback, archive, metadata, tests, docs, and hmmm boundaries. Use when a user asks to replace, rewrite, rebuild, redesign, rename current to *_old, archive old backend/frontend/module/service, create new while retaining old, or when friction shows the old behavior must remain available during a new implementation.
---

# new-retain-old — create new while retaining old

## Purpose

Use this skill when the change is not a simple edit: it creates a new active
surface while keeping the prior surface available as an explicit rollback and
reference object.

The goal is to prevent three failures:

1. deleting useful old behavior before the replacement is proven;
2. hiding uncertainty about what moved, changed, or stayed unresolved;
3. making the new path technically correct but hard to run, test, or review.

## Workflow

1. **Name the active and retained surfaces.**
- Active path: the new implementation users should use now.
- Retained path: the old implementation, usually `<name>_old`, `legacy/`, or
`archive/<date>-<name>`.
- If the user named the retained path, use that exact name.

2. **Inventory before moving.**
- Inspect package metadata, imports, tests, docs, examples, data files, and
entry points.
- Identify what must remain runnable from the retained path.
- Record unknowns as `hmmm`; do not invent certainty.

3. **Move old first, then build new.**
- Preserve the old tree with history-friendly renames where possible.
- Do not leave the active path half-old and half-new unless the user asked
for an incremental migration.
- Keep licenses and data files with the retained implementation unless there
is a clear reason not to.

4. **Declare the new module beside the code.**
- Add `MODULE_BUILD` for the new active module.
- Add `CONTRACTS` for tests the module promises.
- Add `DEPENDENCIES` when imports/calls matter.
- Add `BOUNDARIES` when runtime effects, data, permissions, storage,
network, or admin behavior matter.
- Add `DOCS` when public usage guidance exists or should exist.

5. **Make the new path few-click usable.**
- Provide a copy-paste install/run path.
- Include a smoke example or minimal demo.
- Test the new path from outside the repo root when packaging matters.
- Avoid relying on ambient `PYTHONPATH` unless explicitly documented as a
temporary hmmm boundary.

6. **Test both the promise and the transition.**
- Test core new behavior.
- Test import/dependency boundaries that motivated the rewrite.
- Test that the retained path exists.
- Test docs/examples when they are the user entry point.

7. **Report with a boundary object.**
- Delivered: what is now active, retained, tested, and documented.
- hmmm: unresolved constraints, compatibility gaps, migration risks, or next
continuation steps.

## Required checks before commit

- `git status --short` shows only intentional active/new/retained changes.
- New active path has usage guidance.
- Retained path is named clearly and mentioned in docs or PR text.
- Tests cover at least one behavior of the new path and one transition invariant
such as import hygiene, package self-containment, or retained-path presence.
- Any unresolved behavior is written as `hmmm`, not omitted.

## PR body checklist

Include:

```text
active_path: <path>
retained_path: <path>
rollback: restore retained_path or switch import/entry point back
few_click_path: <commands or hmmm>
tests: <commands>
hmmm: <unresolved constraints or non-empty continuation note>
```

## Anti-patterns

- Calling the old path “backup” without documenting how to restore it.
- Replacing package metadata but not testing installation.
- Adding examples that only work because the agent shell has special paths.
- Flattening `hmmm` into prose that cannot be tested or carried forward.
- Treating archived old code as dead if users still need it for comparison,
rollback, or migration.
4 changes: 4 additions & 0 deletions .agents/skills/new-retain-old/agents/openai.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
interface:
display_name: "New While Retaining Old"
short_description: "Safe replacement with retained old path"
default_prompt: "Use this skill to replace an implementation while preserving the old one, documenting rollback, and testing the transition."
10 changes: 0 additions & 10 deletions backend/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,22 +23,13 @@ fields. If that prints, the backend is installed and usable.
After installation, use the backend directly:

```python
## Usage Guidance

Install or run from this repository with both the repository root and backend
source path on `PYTHONPATH` so the backend can import the UCNS compatibility
module:

```bash
PYTHONPATH="$PWD:$PWD/backend/src" python - <<'PY'
import edcmbone_backend as backend

boundary = backend.make_boundary(
"delivered output",
"remaining constraint to carry forward",
)
print(backend.serialize_boundary(boundary))
PY
```

### Boundary lifecycle
Expand All @@ -59,7 +50,6 @@ PY
- Runtime dependency boundary: active backend source imports only `ucns`.
- Packaging boundary: the backend wheel includes a local `ucns` package so users
do not need to put the repository root on `PYTHONPATH`.
- Runtime dependency boundary: backend source imports only `ucns`.
- Risk boundary: in-memory only; no auth, storage, network, admin, or secret
side effects.
- Documentation and runtime boundaries are declared in msdmd blocks beside the
Expand Down
1 change: 0 additions & 1 deletion backend/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ dependencies = []

[tool.hatch.build.targets.wheel]
packages = ["src/edcmbone_backend", "src/ucns"]
Comment on lines 14 to +15

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge 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 👍 / 👎.

packages = ["src/edcmbone_backend"]

[tool.pytest.ini_options]
testpaths = ["tests"]
5 changes: 0 additions & 5 deletions backend/src/edcmbone_backend/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@
# rollback: restore backend_old as backend
# requires: ucns
# since: 2026-06-25
# unresolved: The requested The-Interdependency/skill-lib path was not present in this checkout; local .agents/skills was used as the msdmd/test-build source.
# unresolved: none; canonical https://github.com/The-Interdependency/skill-lib guidance verified on 2026-06-25
# === END MODULE_BUILD ===

Expand Down Expand Up @@ -175,7 +174,6 @@ def make_boundary(delivered, unresolved=None):
"""Create a UCNS-backed boundary object from delivered and unresolved text."""
unresolved_text = _coerce_text(unresolved)
return BoundaryObject(delivered, hmmm(unresolved_text), _anchor(0 if unresolved_text else 1))
return BoundaryObject(delivered, hmmm(unresolved), _anchor(0 if unresolved else 1))


def merge_boundaries(left, right):
Expand All @@ -184,9 +182,6 @@ def merge_boundaries(left, right):
return BoundaryObject(
"\n".join(part for part in (left.delivered, right.delivered) if part),
hmmm(unresolved),
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),
)

Expand Down
6 changes: 1 addition & 5 deletions backend/src/ucns/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
"""
ucns_v04 — UCNS Engine (turn-fraction angle convention)
========================================================
Angles are stored as Fraction objects representing fractions of a full turn:
0 = 0 deg, 1/4 = 90 deg, 1/2 = 180 deg, 2 = 720 deg = 0 on doubled cover.

Expand Down Expand Up @@ -203,8 +204,3 @@ def multiply(A: UCNSObject, B: UCNSObject) -> UCNSObject:
anchors_pos=tuple(new_anchors),
faces_pos=tuple(new_faces),
)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge 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 👍 / 👎.

"""Compatibility name for the UCNS v0.4 engine."""

from .ucns_v04 import AnchorPayload, UCNSObject, is_unit_payload, multiply, unit_obj

__all__ = ["AnchorPayload", "UCNSObject", "is_unit_payload", "multiply", "unit_obj"]
6 changes: 5 additions & 1 deletion backend/tests/test_backend_contracts.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ def test_boundaries_record_no_hidden_side_effects():


def test_backend_src_path_is_self_contained(tmp_path):
import os
import subprocess
import sys

Expand All @@ -86,10 +87,13 @@ def test_backend_src_path_is_self_contained(tmp_path):
assert boundary.ucns_object.n_min == 1
assert backend.serialize_boundary(boundary)['hmmm']['text'] == 'unresolved'
"""
env = os.environ.copy()
env["PYTHONPATH"] = str(Path(__file__).resolve().parents[1] / "src")
result = subprocess.run(
[sys.executable, "-c", code],
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,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge 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 👍 / 👎.

text=True,
capture_output=True,
check=False,
Expand Down
Loading