feat: wikitool upstream merge/verify - code procedure for taking a stack update (4.5.0-beta.1, #30)
Files changed: - AGENTS.md - CHANGES.md - VERSION - instructions/gates.md - instructions/private-instance.md - tools/CONTRACT.md - tools/README.md - tools/chemenu/cli.py - tools/chemenu/commands/dist_cmd.py - tools/chemenu/commands/run_budget.py - tools/chemenu/commands/upstream_cmd.py - tools/chemenu/ownership.py - tools/chemenu/tests/test_upstream_cmd.py
This commit is contained in:
@@ -39,7 +39,7 @@ from typing import Callable, NamedTuple, Optional, Union
|
||||
|
||||
import typer
|
||||
|
||||
from chemenu import config, conventions, kb_collections, kb_state, version as version_mod
|
||||
from chemenu import config, conventions, kb_collections, kb_state, ownership, version as version_mod
|
||||
from chemenu.commands._util import fail, rel_path, success, today_iso
|
||||
|
||||
app = typer.Typer(help="Build a distributable copy of the wiki machinery.")
|
||||
@@ -132,8 +132,15 @@ INSTRUCTIONS_EXCLUDE_DIRS = {"dev"}
|
||||
RAW_SUBDIRS = ("articles", "documents", "notes", "assets")
|
||||
|
||||
# Stage contracts that are not collections and carry no pages: copied as a
|
||||
# single file each, nothing else from their directory.
|
||||
CONTRACT_ONLY_STAGES = ("raw/CONTRACT.md", "reports/CONTRACT.md", "work/CONTRACT.md")
|
||||
# single file each, nothing else from their directory. `kb/` is excluded here
|
||||
# - it is a content stage too, but it has collections underneath it, so its
|
||||
# contract is handled by `build_plan` alongside them rather than as a bare
|
||||
# stage copy. Derived from `ownership.CONTENT_STAGES` rather than listed
|
||||
# again, so the set this loop copies and the set `upstream merge` restores
|
||||
# cannot name a different stage without one of them failing its own test.
|
||||
CONTRACT_ONLY_STAGES = tuple(
|
||||
f"{stage}/CONTRACT.md" for stage in ownership.CONTENT_STAGES if stage != "kb"
|
||||
)
|
||||
|
||||
# Single tracked files copied out of an otherwise-untouched, partially-ignored
|
||||
# directory. `.claude/` holds the harness's own session-tracing config
|
||||
@@ -439,19 +446,20 @@ def build_plan(origin: Optional[Origin] = None) -> dict[str, PlannedFile]:
|
||||
# appears in INSTALL.md and version.py, so such a scan would either whitelist
|
||||
# the very string it is looking for or cry wolf on every export.
|
||||
#
|
||||
# `COLLECTION.md` and `CONVENTIONS.md` are deliberately *not* on the allowed
|
||||
# list any more. Both bind, and both are the instance's to write, so they cross
|
||||
# the boundary as `.template` and are adopted by a rename - a plan carrying the
|
||||
# `COLLECTION.md` and `CONVENTIONS.md` are deliberately *not* allowed through
|
||||
# any more. Both bind, and both are the instance's to write, so they cross the
|
||||
# boundary as `.template` and are adopted by a rename - a plan carrying the
|
||||
# filled name would hand a new instance this one's authoring conventions as
|
||||
# though they were the stack's.
|
||||
#
|
||||
# What counts as machinery under kb/ or raw/ is no longer a second list here:
|
||||
# it is `ownership.is_stack_owned`, the same predicate `upstream merge` and
|
||||
# `upstream verify` restore/check against. Only the export-only stubs
|
||||
# (`ownership.EXPORT_STUB_NAMES`) are allowed here without also being
|
||||
# stack-owned - a merge keeps the *local* copy of those, while export writes a
|
||||
# fresh one regardless of either side, so the two callers genuinely disagree
|
||||
# about them and each keeps its own allowance for that one case.
|
||||
_CONTENT_PREFIXES = ("kb/", "raw/")
|
||||
_CONTENT_ALLOWED_NAMES = (
|
||||
"CONTRACT.md",
|
||||
f"{kb_collections.CONTRACT_NAME}.template",
|
||||
conventions.CONVENTIONS_TEMPLATE,
|
||||
"log.md",
|
||||
".gitkeep",
|
||||
)
|
||||
_INSTANCE_OWNED_KB_FILES = (kb_collections.CONTRACT_NAME, conventions.CONVENTIONS_FILENAME)
|
||||
|
||||
|
||||
@@ -473,7 +481,11 @@ def find_leaks(plan: dict[str, PlannedFile]) -> list[str]:
|
||||
leaks.append(f"{relative} (this instance's page type-spec; ship the .template)")
|
||||
elif relative.startswith("instructions/dev/"):
|
||||
leaks.append(f"{relative} (stack-development only)")
|
||||
elif relative.startswith(_CONTENT_PREFIXES) and name not in _CONTENT_ALLOWED_NAMES:
|
||||
elif (
|
||||
relative.startswith(_CONTENT_PREFIXES)
|
||||
and not ownership.is_stack_owned(relative)
|
||||
and not ownership.is_export_stub(name)
|
||||
):
|
||||
leaks.append(f"{relative} (wiki content, not machinery)")
|
||||
return leaks
|
||||
|
||||
|
||||
Reference in New Issue
Block a user