Merge pull request 'One work log per bundle: the rule, the gate that enforces it, and the second log it came out of' (#57) from docs/single-work-log-rule into main
This commit was merged in pull request #57.
This commit is contained in:
commit
ab94c91bcf
10 files changed
+187
-44
No files matched your search
+13
-1
@@ -4,7 +4,15 @@ import re, sys
|
||||
from pathlib import Path
|
||||
kb = Path(sys.argv[1])
|
||||
issues = []
|
||||
dirs = sorted({p.parent for p in kb.rglob("*.md")})
|
||||
|
||||
|
||||
def kept(p):
|
||||
# `.AGENTTRASH/` is quarantine, not bundle content: a gate that flags it pushes an
|
||||
# agent to delete a page that is only waiting for a pruning session with the operator.
|
||||
return ".AGENTTRASH" not in p.parts
|
||||
|
||||
|
||||
dirs = sorted({p.parent for p in kb.rglob("*.md") if kept(p)})
|
||||
for d in dirs:
|
||||
idx = d / "index.md"
|
||||
if not idx.is_file() and d != kb:
|
||||
@@ -21,12 +29,16 @@ for d in dirs:
|
||||
# wikilinks too
|
||||
wl_names = {m.group(1).strip().rsplit("/", 1)[-1] for m in re.finditer(r"\[\[([^\]|#]+)", text)}
|
||||
for sib in sorted(d.iterdir()):
|
||||
if sib.name == ".AGENTTRASH":
|
||||
continue
|
||||
if sib.suffix != ".md" or sib.name == "index.md":
|
||||
continue
|
||||
if sib.resolve() not in linked and sib.stem not in wl_names:
|
||||
issues.append(f"{d.relative_to(kb)}/index.md: does not link {sib.name}")
|
||||
# subdirs of d linked as their index?
|
||||
for sub in sorted(d.iterdir()):
|
||||
if sub.name == ".AGENTTRASH":
|
||||
continue
|
||||
if sub.is_dir() and (sub / "index.md").is_file():
|
||||
subidx = (sub / "index.md").resolve()
|
||||
dirref = sub.resolve()
|
||||
|
||||
+22
-2
@@ -12,7 +12,15 @@ from pathlib import Path
|
||||
kb = Path(sys.argv[1])
|
||||
violations = []
|
||||
|
||||
for p in sorted(kb.rglob("*.md")):
|
||||
def pages():
|
||||
"""Markdown pages that belong to the bundle. `.AGENTTRASH/` is a quarantine, not
|
||||
content: linting a deleted-but-not-yet-pruned page would demand its destruction to
|
||||
make the gate go green, which is the wrong incentive."""
|
||||
for p in kb.rglob("*.md"):
|
||||
if ".AGENTTRASH" not in p.parts:
|
||||
yield p
|
||||
|
||||
for p in pages():
|
||||
rel = p.relative_to(kb)
|
||||
text = p.read_text(errors="replace")
|
||||
lines = text.splitlines()
|
||||
@@ -38,9 +46,21 @@ for p in sorted(kb.rglob("*.md")):
|
||||
if not isinstance(fm, dict) or not str(fm.get("type", "")).strip():
|
||||
violations.append(f"{rel}: frontmatter lacks required 'type:'")
|
||||
|
||||
|
||||
# One work log per bundle, at the bundle root. A `log.md` is a reserved name, but
|
||||
# reserved does not mean "allowed in every directory": per-directory logs are how a
|
||||
# bundle ends up with fifty of them, the entry never where the next agent looks, and
|
||||
# each copy dating the same event differently. A bundle with no log at all is left to
|
||||
# the maintenance page to nag about; this gate's job is sprawl.
|
||||
logs = sorted(str(p.relative_to(kb)) for p in pages() if p.name == "log.md")
|
||||
if len(logs) > 1 or (logs and logs[0] != "log.md"):
|
||||
violations.append(
|
||||
"a bundle has one work log, log.md, at the bundle root; found: " + ", ".join(logs)
|
||||
)
|
||||
|
||||
# link integrity: fenced code blocks hold example paths, not live links — strip first.
|
||||
# Vendored spec is exempt: its example paths are illustrations, not live links.
|
||||
for p in sorted(kb.rglob("*.md")):
|
||||
for p in pages():
|
||||
if str(p.relative_to(kb)) == "references/okf-spec.md":
|
||||
continue
|
||||
text = re.sub(r"^```[^\n]*$^```[^\n]*$", "", p.read_text(errors="replace"), flags=re.M)
|
||||
|
||||
Reference in new issue
Block a user