Skip to content

Commit 760c78d

Browse files
committed
cli
1 parent fb5f436 commit 760c78d

5 files changed

Lines changed: 111 additions & 37 deletions

File tree

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,8 @@ git tag -d vX.Z.Y
187187
git push origin :refs/tags/vX.Z.Y
188188
```
189189

190+
## Links
191+
190192
[Unreleased]: https://github.com/structural-explainability/se-theory-neutral-substrate/compare/v0.5.0...HEAD
191193
[0.5.0]: https://github.com/structural-explainability/se-theory-neutral-substrate/compare/v0.3.0...v0.5.0
192194
[0.4.0]: https://github.com/structural-explainability/se-theory-neutral-substrate/compare/v0.3.0...v0.4.0

README.md

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,9 @@ import NeutralSubstrate
8282

8383
## Build
8484

85+
Use VS Code Menu:
86+
View / Command Palette / `Developer: Reload Window` to refresh.
87+
8588
```shell
8689
elan self update
8790
lake update
@@ -135,21 +138,20 @@ uvx pre-commit run --all-files
135138
git add -A
136139
uvx pre-commit run --all-files
137140

138-
uv run se-manifest-validate
139-
uv run se-manifest-validate --strict
140-
uv run se-manifest-validate --require-tag
141-
142-
uv run se-manifest-version-sync
143-
141+
# OPTIONAL:
144142
# Scaffold reference/ artifacts from Lean 4 source.
145-
# Adds stubs for new symbols. Preserves existing descriptions and cite_ids.
146-
uv run se-ref-scaffold
143+
# Adds stubs for new symbols.
144+
# Preserves existing descriptions, names, and cite_ids.
147145
uv run se-ref-scaffold --dry-run
146+
uv run se-ref-scaffold
147+
148+
# OPTIONAL OVERWRITE:
149+
# Use carefully. Re-derives scaffolded fields and may overwrite
150+
# existing descriptions, names, and cite_ids.
148151
uv run se-ref-scaffold --overwrite
149152

150-
# Validate reference/ artifacts against Lean 4 source. Writes nothing.
151-
uv run se-ref-validate
152-
uv run se-ref-validate --strict
153+
# IMPORTANT: Run checks
154+
uv run se-validate --strict
153155

154156
# do chores
155157
uv run python -m pyright

pyproject.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,8 @@ docs = [
4040
]
4141

4242
[project.scripts]
43-
se-manifest-validate = "se_theory_neutral_substrate.cli:validate_main"
43+
se-validate = "se_theory_neutral_substrate.cli:validate_main"
44+
se-manifest-schema-validate = "se_theory_neutral_substrate.cli:schema_validate_main"
4445
se-manifest-version-sync = "se_theory_neutral_substrate.cli:sync_main"
4546
se-ref-scaffold = "se_theory_neutral_substrate.cli:ref_scaffold_main"
4647
se-ref-validate = "se_theory_neutral_substrate.cli:ref_validate_main"

src/se_theory_neutral_substrate/cli.py

Lines changed: 51 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,31 @@
1-
"""cli.py - Command-line interface for se-manifest-schema.
1+
"""cli.py - Command-line interface for se-theory-identity-regimes.
22
3-
Parses arguments and dispatches to orchestrate.py or sync.py.
4-
Owns nothing except argument parsing and error handling.
5-
All logic lives in orchestrate.py and sync.py.
3+
Parses arguments and dispatches to repository validation, manifest-schema
4+
validation, version sync, and reference artifact tooling.
65
76
Entry points:
8-
uv run se-manifest-validate
9-
uv run se-manifest-validate --strict
10-
uv run se-manifest-validate --require-tag
7+
uv run se-validate
8+
uv run se-validate --strict
9+
uv run se-validate --require-tag
10+
11+
uv run se-manifest-schema-validate
12+
uv run se-manifest-schema-validate --strict
13+
uv run se-manifest-schema-validate --require-tag
1114
1215
uv run se-manifest-version-sync
1316
14-
uv run se-ref-scaffold
1517
uv run se-ref-scaffold --dry-run
18+
uv run se-ref-scaffold
1619
uv run se-ref-scaffold --overwrite
1720
1821
uv run se-ref-validate
1922
uv run se-ref-validate --strict
20-
21-
Call chain:
22-
__main__.py -> cli.main()
23-
-> orchestrate.run_validate() (sync_all called internally)
24-
-> sync.sync_all() (sync only, no validation)
25-
-> reference.run_scaffold() (scaffold + validate reference/)
26-
-> reference.run_ref_validate() (validate reference/ only)
2723
"""
2824

2925
import argparse
3026
import sys
3127

28+
from se_manifest_schema.orchestrate import run_validate as run_validate_manifest
3229
from se_manifest_schema.sync import sync_all
3330

3431
from se_theory_neutral_substrate.orchestrate import run_validate
@@ -43,9 +40,10 @@ def build_parser() -> argparse.ArgumentParser:
4340
)
4441
subparsers = parser.add_subparsers(dest="command")
4542

43+
# -- validate ------------------------------------------------------------
4644
validate_parser = subparsers.add_parser(
4745
"validate",
48-
help="Sync and validate manifest-schema.toml and SE_MANIFEST.toml.",
46+
help="Run full repository validation.",
4947
)
5048
validate_parser.add_argument(
5149
"--strict",
@@ -58,12 +56,29 @@ def build_parser() -> argparse.ArgumentParser:
5856
help="Require CITATION.cff version to match current git tag.",
5957
)
6058

59+
# -- schema-validate -----------------------------------------------------
60+
schema_validate_parser = subparsers.add_parser(
61+
"schema-validate",
62+
help="Validate only the manifest schema layer.",
63+
)
64+
schema_validate_parser.add_argument(
65+
"--strict",
66+
action="store_true",
67+
help="Treat warnings as errors.",
68+
)
69+
schema_validate_parser.add_argument(
70+
"--require-tag",
71+
action="store_true",
72+
help="Require CITATION.cff version to match current git tag.",
73+
)
74+
75+
# -- sync ----------------------------------------------------------------
6176
subparsers.add_parser(
6277
"sync",
6378
help="Sync pyproject.toml fallback-version from CITATION.cff version.",
6479
)
6580

66-
# -- ref-scaffold -------------------------------------------------------------
81+
# -- ref-scaffold --------------------------------------------------------
6782
ref_scaffold_parser = subparsers.add_parser(
6883
"ref-scaffold",
6984
help=(
@@ -83,7 +98,7 @@ def build_parser() -> argparse.ArgumentParser:
8398
help="Overwrite existing descriptions, names, and cite_ids with re-derived values.",
8499
)
85100

86-
# -- ref-validate ---------------------------------------------------------
101+
# -- ref-validate --------------------------------------------------------
87102
ref_validate_parser = subparsers.add_parser(
88103
"ref-validate",
89104
help=(
@@ -94,19 +109,24 @@ def build_parser() -> argparse.ArgumentParser:
94109
ref_validate_parser.add_argument(
95110
"--strict",
96111
action="store_true",
97-
help="Treat warnings (orphaned symbols, missing stubs) as errors.",
112+
help="Treat warnings as errors.",
98113
)
99114

100115
return parser
101116

102117

103118
def validate_main() -> int:
104-
"""Validate the manifest schema and sync if needed. Returns 0 on success, 1 on error."""
119+
"""Run full repository validation. Returns 0 on success, 1 on error."""
105120
return main(["validate"] + sys.argv[1:])
106121

107122

123+
def schema_validate_main() -> int:
124+
"""Validate only the manifest schema layer. Returns 0 on success, 1 on error."""
125+
return main(["schema-validate"] + sys.argv[1:])
126+
127+
108128
def sync_main() -> int:
109-
"""Sync the manifest schema. Returns 0 on success, 1 on error."""
129+
"""Sync version metadata. Returns 0 on success, 1 on error."""
110130
return main(["sync"] + sys.argv[1:])
111131

112132

@@ -124,7 +144,7 @@ def main(argv: list[str] | None = None) -> int:
124144
"""Run the command-line interface.
125145
126146
Returns:
127-
0 on success, 1 on error, 2 if no command given.
147+
0 on success, 1 on error, 2 if no command is given.
128148
"""
129149
parser = build_parser()
130150
args = parser.parse_args(argv)
@@ -135,14 +155,23 @@ def main(argv: list[str] | None = None) -> int:
135155
strict=args.strict,
136156
require_tag=args.require_tag,
137157
)
158+
159+
if args.command == "schema-validate":
160+
return run_validate_manifest(
161+
strict=args.strict,
162+
require_tag=args.require_tag,
163+
)
164+
138165
if args.command == "sync":
139166
sync_all()
140167
return 0
168+
141169
if args.command == "ref-scaffold":
142170
return run_scaffold(
143171
dry_run=args.dry_run,
144172
overwrite=args.overwrite,
145173
)
174+
146175
if args.command == "ref-validate":
147176
return run_ref_validate(
148177
strict=args.strict,

src/se_theory_neutral_substrate/reference.py

Lines changed: 43 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,42 @@ def _infer_core_module(surface_module: str) -> str:
123123
return surface_module.replace("Surface", "Core")
124124

125125

126+
def _path_to_module(path: Path, lean_root: Path) -> str:
127+
rel = path.relative_to(lean_root).with_suffix("")
128+
return ".".join(rel.parts)
129+
130+
131+
def _infer_core_modules(surface_module: str, lean_root: Path) -> list[str]:
132+
"""Infer Core modules under the surface namespace.
133+
134+
Supports both layouts:
135+
136+
- MyLib/Core.lean -> MyLib.Core
137+
- MyLib/Profile/Core.lean -> MyLib.Profile.Core
138+
- MyLib/Transform/Core.lean -> MyLib.Transform.Core
139+
140+
The root Core.lean file is sorted first when present, followed by
141+
nested Core.lean files in deterministic path order.
142+
"""
143+
if not surface_module.endswith(".Surface"):
144+
return []
145+
146+
root_module = surface_module.removesuffix(".Surface")
147+
root_dir = lean_root.joinpath(*root_module.split("."))
148+
149+
if not root_dir.exists():
150+
return []
151+
152+
core_files = sorted(root_dir.rglob("Core.lean"))
153+
154+
root_core = root_dir / "Core.lean"
155+
if root_core in core_files:
156+
core_files.remove(root_core)
157+
core_files.insert(0, root_core)
158+
159+
return [_path_to_module(path, lean_root) for path in core_files]
160+
161+
126162
def _kind_to_section(artifact_kind: str) -> str:
127163
"""'substrate-type-registry' -> 'type', 'se-theorem-registry' -> 'theorem'."""
128164
without_suffix = artifact_kind.removesuffix("-registry")
@@ -303,9 +339,13 @@ def _process_artifact(
303339
source_modules = _source_modules_in_registry(existing_data)
304340
if not source_modules:
305341
surface = existing_data.get("surface_module", index_surface_module)
306-
derived = _infer_core_module(surface)
307-
source_modules = [derived]
308-
result.note(f"source module inferred: {derived}")
342+
source_modules = _infer_core_modules(surface, lean_root)
343+
if source_modules:
344+
result.note("source modules inferred: " + ", ".join(source_modules))
345+
else:
346+
derived = surface.replace("Surface", "Core")
347+
source_modules = [derived]
348+
result.note(f"source module inferred: {derived}")
309349

310350
# Scan Lean files
311351
all_decls: list[LeanDecl] = []

0 commit comments

Comments
 (0)