You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@juneau.apache.org by ja...@apache.org on 2026/08/25 11:40:00 UTC

(juneau) branch master updated: Point leftover CodeQL comments and todo scripts at ~/Project Work trackers.

This is an automated email from the ASF dual-hosted git repository.

jamesbognar pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/juneau.git


The following commit(s) were added to refs/heads/master by this push:
     new eda0395106 Point leftover CodeQL comments and todo scripts at ~/Project Work trackers.
eda0395106 is described below

commit eda0395106385efe2162570da5f0c0ce3bef2427
Author: James Bognar <ja...@apache.org>
AuthorDate: Tue Aug 25 07:39:52 2026 -0400

    Point leftover CodeQL comments and todo scripts at ~/Project Work trackers.
---
 .../models/path-injection.yml                      |   2 +-
 .../apache/juneau-security-models/qlpack.yml       |   2 +-
 scripts/perf-required.py                           |   8 +-
 scripts/todo-next-id.py                            | 151 +++++++++++++--------
 scripts/todo-status-audit.py                       |  24 ++--
 5 files changed, 110 insertions(+), 77 deletions(-)

diff --git a/.github/codeql/apache/juneau-security-models/models/path-injection.yml b/.github/codeql/apache/juneau-security-models/models/path-injection.yml
index 79c4639e3c..78e1e615d4 100644
--- a/.github/codeql/apache/juneau-security-models/models/path-injection.yml
+++ b/.github/codeql/apache/juneau-security-models/models/path-injection.yml
@@ -24,7 +24,7 @@
 # (already-boundary-checked) target does not exist. It is a genuine cross-method
 # sanitizer, but CodeQL's stock java/path-injection query has no way to know that
 # without this model, so every reachable call site had to be manually dismissed as
-# a false positive (see .work/todo/finished/FINISHED-235-codeql-security-alert-remediation.md,
+# a false positive (see ~/Project Work/finished/juneau/FINISHED-J0235-codeql-security-alert-remediation.md,
 # alerts #91, #93, #321-#328) -- and those dismissals don't survive a file move, as
 # proven by TODO-236 re-spawning #322-#328 under fresh ids.
 extensions:
diff --git a/.github/codeql/apache/juneau-security-models/qlpack.yml b/.github/codeql/apache/juneau-security-models/qlpack.yml
index 386adc9757..ed65403db2 100644
--- a/.github/codeql/apache/juneau-security-models/qlpack.yml
+++ b/.github/codeql/apache/juneau-security-models/qlpack.yml
@@ -23,7 +23,7 @@
 # `.github/workflows/codeql-analysis.yml` (see the comment there for why the
 # `packs:` field in a codeql-config.yml cannot be used for unpublished local packs).
 #
-# See TODO-240 (.work/todo/TODO-240-codeql-resolvesafely-sanitizer-model.md) for the
+# See TODO-J0240 (~/Project Work/finished/juneau/FINISHED-J0240-codeql-resolvesafely-sanitizer-model.md) for the
 # motivating context.
 name: apache/juneau-security-models
 version: 0.0.1
diff --git a/scripts/perf-required.py b/scripts/perf-required.py
index 1ca78705e8..2e5c94b91b 100644
--- a/scripts/perf-required.py
+++ b/scripts/perf-required.py
@@ -14,8 +14,8 @@
 """
 "## Perf section" requirement checker, for FINISHED archive entries.
 
-Mirrors ONE of the two trigger conditions from agents/skills/juneau-todo-management/SKILL.md's
-"## Perf section in FINISHED archives": "the implementation touches any file in the perf-sensitive
+Mirrors ONE of the two trigger conditions from ~/Project Work/skills/todo-and-waves/SKILL.md
+(Juneau FINISHED `## Perf`): "the implementation touches any file in the perf-sensitive
 hot-path inventory". It deliberately does NOT attempt the OTHER trigger ("the landing changes the
 test count by more than 50 tests") -- that requires comparing against the prior FINISHED archive's
 stated test count, which isn't mechanically derivable from a diff. Keep checking that one by hand.
@@ -66,8 +66,8 @@ from pathlib import Path
 
 REPO_ROOT = Path(__file__).resolve().parent.parent
 
-# Kept in sync with agents/skills/juneau-todo-management/SKILL.md's "## Perf section in FINISHED
-# archives" hot-path inventory. Matched by basename only (these class names are unique enough
+# Kept in sync with ~/Project Work/skills/todo-and-waves/SKILL.md Juneau FINISHED `## Perf`
+# hot-path inventory. Matched by basename only (these class names are unique enough
 # across the repo that a full-path match would just add fragility for no benefit).
 HOT_PATH_FILES = (
     "RestContext.java",
diff --git a/scripts/todo-next-id.py b/scripts/todo-next-id.py
index 485a2ee5c6..fb593abba0 100755
--- a/scripts/todo-next-id.py
+++ b/scripts/todo-next-id.py
@@ -12,21 +12,19 @@
 # * specific language governing permissions and limitations under the License.
 # ***************************************************************************************************************************
 """
-Next-free TODO-id calculator for this repository's .work/todo/ tracker.
+Next-free TODO-id calculator for this project's tracker under ~/Project Work/todos/juneau/.
 
-Repo-agnostic: the repository root is derived from this file's own location
-(<root>/scripts/todo-next-id.py -> <root>), never hardcoded, so the same body works in
-every repository that adopts the convention. Only the REPO_LABEL / SKILL_NAME constants
-below and the license header differ between copies.
+Trackers live in ~/Project Work (todos/<slug>/ + finished/<slug>/), not in the repo.
+Only REPO_LABEL / SKILL_NAME / ID_PROJECT_LETTER / TRACKER_SLUG differ between copies.
+CUs read ~/Project Work; do not copy .work/todo into clones.
 
-**Ids are per-repository and start at 1 in each.** This script only ever scans the tree it
-lives in. It prints the resolved root to stderr on every run precisely so that a run made
-from the wrong working tree is visible rather than silent.
+**Ids are per-project and start at 1 in each.** This script scans ~/Project Work/todos/<slug>
+and ~/Project Work/finished/<slug>. It prints those paths to stderr on every run.
 
 Mirrors the exact scan scope documented in this repo's TODO-management skill, in its
 "Adding a new item" and "MAYBE Numbering" sections:
 
-  1. Every "[TODO-n]" and bare "TODO-n" token in .work/todo/TODO.md (a trailing lowercase
+  1. Every "[TODO-n]" and bare "TODO-n" token in ~/Project Work/todos/juneau/TODO.md (a trailing lowercase
      letter suffix, e.g. "TODO-174a", is stripped -- only the numeric part counts). A
      qualified cross-repo citation such as "juneau:TODO-42" is NOT counted; it names an id in
      another repo's tracker.
@@ -35,15 +33,15 @@ Mirrors the exact scan scope documented in this repo's TODO-management skill, in
      "for example, TODO-5" anywhere in TODO.md permanently consumes id 5. Write "TODO-<n>" in
      prose.
   2. Every "TODO-"/"READY-"/"MAYBE-"/"HOLD-"/"FINISHED-"/"CANCELLED-<n>[<letter>]-*.md" filename
-     directly under .work/todo/ and .work/todo/finished/.
+     directly under ~/Project Work/todos/juneau/ and ~/Project Work/finished/juneau/.
 
 next = 1 + max(all numeric ids found). A child's letter suffix (TODO-174a, FINISHED-337f, ...)
 is ignored for this computation -- only its numeric part counts, per the skill's "Numbering"
 rule -- so promoting/splitting a lettered child never consumes a new sequential id.
 
-.work/ is gitignored, so this is pure filesystem/text scanning; no git needed.
+Trackers are outside the git repo (~/Project Work); this is a pure filesystem scan.
 
-A MISSING .work/todo/ directory is a hard error (exit 2), not an empty scan. Silently
+A MISSING ~/Project Work/todos/juneau/ directory is a hard error (exit 2), not an empty scan. Silently
 returning "1" from a tree that has no tracker is how ids get reused: it is the correct answer
 in a freshly-seeded repo and a catastrophic one in a repo whose tracker you failed to find.
 Pass --allow-missing if you genuinely want the empty-tree answer.
@@ -52,21 +50,21 @@ Usage:
     ./scripts/todo-next-id.py
     ./scripts/todo-next-id.py --list
     ./scripts/todo-next-id.py --check 12
-    ./scripts/todo-next-id.py --root /path/to/other/repo
+    ./scripts/todo-next-id.py --root ~/Project Work
 
 Options:
-    --root <path>   Repository root to scan (default: the parent of this script's directory).
+    --root <path>   Project Work root (default: ~/Project Work).
     --list          Print every id currently in use (letter suffixes preserved), one per
                     line, sorted numerically then by letter, instead of the next free id.
     --check <id>    Exit 1 with a message if <id> (e.g. "12" or "7a"; a leading "TODO-"
                     is tolerated) is already in use; exit 0 with a message if it's free.
-    --allow-missing Treat an absent .work/todo/ as an empty tracker instead of an error.
+    --allow-missing Treat an absent ~/Project Work/todos/juneau/ as empty instead of an error.
     --help, -h      Show this help message.
 
 Exit status:
     0   Success (or --check found the id free).
     1   --check found the id already taken, or a malformed --check argument.
-    2   .work/todo/ does not exist under the resolved root (and --allow-missing was not given).
+    2   ~/Project Work/todos/juneau/ does not exist (and --allow-missing was not given).
 """
 
 from __future__ import annotations
@@ -81,25 +79,35 @@ from pathlib import Path
 # copy of this script; keep it that way so a fix lands once and is copied verbatim.
 # ---------------------------------------------------------------------------------------
 REPO_LABEL = "Apache Juneau"
-SKILL_NAME = "juneau-todo-management"
-
-DEFAULT_REPO_ROOT = Path(__file__).resolve().parent.parent
-
-# "[TODO-42]" or bare "TODO-42" in TODO.md prose. A trailing run of lowercase letters (the
-# child-letter suffix, possibly more than one for grandchildren like "17fa") is captured
-# separately so it can be preserved for --list/--check but ignored for numbering.
+SKILL_NAME = "todo-and-waves"
+# Project letter in the id: Juneau = "J" (TODO-Jnnnn). Other projects: "C" Console,
+# "R" Release App, "I" IRS. Numeric part is always 4 digits. This scanner matches only
+# TODO-J<digits>, so TODO-C0015 / TODO-R0001 / TODO-I0001 are not counted here.
+ID_PROJECT_LETTER = "J"
+TRACKER_SLUG = "juneau"
+
+PROJECT_WORK = Path.home() / "Project Work"
+
+# "[TODO-J0042]" or bare "TODO-J0042" in TODO.md prose. Digits follow the project letter J.
+# A trailing child-letter suffix (TODO-J0174a) is captured separately so it can be preserved
+# for --list/--check but ignored for numbering.
 #
-# The leading lookbehind rejects a qualified cross-repo citation -- "juneau:TODO-42",
-# "support-console:TODO-42" -- which names an id in ANOTHER repo's tracker and must not
-# consume one here. Ids are bare and per-repository, so without this the act of writing down
-# that another repo's item blocks you would silently burn a local id.
-TODO_TOKEN_RE = re.compile(r"(?<![\w:])TODO-(\d+)([a-z]*)\b")
+# The leading lookbehind rejects a qualified cross-repo citation -- "juneau:TODO-J0042",
+# "support-console:TODO-C0015" -- which names an id in ANOTHER repo's tracker and must not
+# consume one here.
+TODO_TOKEN_RE = re.compile(r"(?<![\w:])TODO-J(\d+)([a-z0-9]*)\b")
 
-# Every lifecycle-state filename directly under .work/todo/ or .work/todo/finished/.
-FILENAME_RE = re.compile(r"^(?:TODO|READY|MAYBE|HOLD|FINISHED|CANCELLED)-(\d+)([a-z]*)-.*\.md$")
+# Every lifecycle-state filename under ~/Project Work/todos/juneau/ or finished/juneau/.
+FILENAME_RE = re.compile(
+    r"^(?:TODO|READY|MAYBE|HOLD|FINISHED|CANCELLED|NEED_INPUT)-J(\d+)([a-z0-9]*)-.*\.md$"
+)
 
+# Migration to TODO-Jnnnn is complete. Do not scan unprefixed TODO-<digits>.
+LEGACY_TODO_TOKEN_RE = None
+LEGACY_FILENAME_RE = None
 
-def collect_ids(todo_dir: Path) -> tuple[set, set]:
+
+def collect_ids(todo_dir: Path, finished_dir: Path | None = None) -> tuple[set, set]:
     """
     Scan every source described in the module docstring.
 
@@ -112,66 +120,90 @@ def collect_ids(todo_dir: Path) -> tuple[set, set]:
     raw_ids = set()
     numeric_ids = set()
 
+    def _record(regex, source, *, filename=False):
+        if regex is None:
+            return
+        matches = (regex.match(source),) if filename else regex.finditer(source)
+        for m in matches:
+            if not m:
+                continue
+            raw_ids.add(str(int(m.group(1))) + m.group(2))
+            numeric_ids.add(int(m.group(1)))
+
     todo_md = todo_dir / "TODO.md"
     if todo_md.is_file():
         text = todo_md.read_text(encoding="utf-8")
-        for m in TODO_TOKEN_RE.finditer(text):
-            raw_ids.add(m.group(1) + m.group(2))
-            numeric_ids.add(int(m.group(1)))
+        _record(TODO_TOKEN_RE, text)
+        _record(LEGACY_TODO_TOKEN_RE, text)
 
-    for directory in (todo_dir, todo_dir / "finished"):
+    dirs = [todo_dir, finished_dir if finished_dir is not None else todo_dir / "finished"]
+    for directory in dirs:
         if not directory.is_dir():
             continue
         for entry in directory.iterdir():
             if not entry.is_file():
                 continue
-            m = FILENAME_RE.match(entry.name)
-            if not m:
-                continue
-            raw_ids.add(m.group(1) + m.group(2))
-            numeric_ids.add(int(m.group(1)))
+            _record(FILENAME_RE, entry.name, filename=True)
+            _record(LEGACY_FILENAME_RE, entry.name, filename=True)
 
     return raw_ids, numeric_ids
 
 
 def sort_key(raw_id: str):
     """Sort key for a raw id string: numeric part first, then its letter suffix."""
-    m = re.match(r"^(\d+)([a-z]*)$", raw_id)
+    m = re.match(r"^(\d+)([a-z0-9]*)$", raw_id)
     if not m:
         return (0, raw_id)
     return (int(m.group(1)), m.group(2))
 
 
+def format_id(raw_id: str) -> str:
+    """Format a stored raw id as letter + 4-digit number + child suffix (e.g. J0447, J0445o)."""
+    m = re.match(r"^(\d+)([a-z0-9]*)$", raw_id)
+    if not m:
+        return f"{ID_PROJECT_LETTER}{raw_id}" if ID_PROJECT_LETTER else raw_id
+    return f"{ID_PROJECT_LETTER}{int(m.group(1)):04d}{m.group(2)}"
+
+
 def normalize_check_id(raw: str) -> str | None:
-    """Normalize a --check argument (optionally "TODO-"-prefixed) to a bare "<digits><letters>" id, or None if malformed."""
+    """Normalize a --check argument to a bare "<digits><letters>" id, or None if malformed.
+
+    Accepts `12`, `7a`, `TODO-12`, and (for prefixed projects) `C12` / `TODO-C12`.
+    """
     candidate = raw.strip()
     if candidate.upper().startswith("TODO-"):
         candidate = candidate[len("TODO-"):]
-    m = re.match(r"^(\d+)([a-zA-Z]*)$", candidate)
+    if (
+        ID_PROJECT_LETTER
+        and len(candidate) >= 2
+        and candidate[0].upper() == ID_PROJECT_LETTER
+        and candidate[1].isdigit()
+    ):
+        candidate = candidate[1:]
+    m = re.match(r"^(\d+)([a-z0-9]*)$", candidate, re.I)
     if not m:
         return None
-    return m.group(1) + m.group(2).lower()
+    return str(int(m.group(1))) + m.group(2).lower()
 
 
 def main():
     parser = argparse.ArgumentParser(
-        description=f"Compute the next free .work/todo/ TODO id for {REPO_LABEL} (see @{SKILL_NAME}).",
+        description=f"Compute the next free TODO id for {REPO_LABEL} under ~/Project Work (see @{SKILL_NAME}).",
         epilog=__doc__,
         formatter_class=argparse.RawDescriptionHelpFormatter,
     )
-    parser.add_argument("--root", metavar="PATH", help="Repository root to scan (default: parent of this script's directory).")
+    parser.add_argument("--root", metavar="PATH", help="Project Work root (default: ~/Project Work).")
     parser.add_argument("--list", action="store_true", help="Print every id currently in use, sorted.")
     parser.add_argument("--check", metavar="ID", help="Exit non-zero if ID is already taken.")
-    parser.add_argument("--allow-missing", action="store_true", help="Treat an absent .work/todo/ as empty instead of an error.")
+    parser.add_argument("--allow-missing", action="store_true", help="Treat an absent tracker as empty instead of an error.")
     args = parser.parse_args()
 
-    repo_root = Path(args.root).resolve() if args.root else DEFAULT_REPO_ROOT
-    todo_dir = repo_root / ".work" / "todo"
+    project_work = Path(args.root).expanduser().resolve() if args.root else PROJECT_WORK
+    todo_dir = project_work / "todos" / TRACKER_SLUG
+    finished_dir = project_work / "finished" / TRACKER_SLUG
 
-    # Always announce the tree actually scanned. Ids are per-repository and bare, so
-    # "TODO-5" is a different item in each repo; a wrong-tree run must not look identical
-    # to a right-tree one. stderr, so `NEXT=$(./scripts/todo-next-id.py)` still works.
-    print(f"[{REPO_LABEL}] scanning {todo_dir}", file=sys.stderr)
+    # Always announce the tree actually scanned. stderr, so NEXT=$(./scripts/todo-next-id.py) still works.
+    print(f"[{REPO_LABEL}] scanning {todo_dir} + {finished_dir}", file=sys.stderr)
 
     if not todo_dir.is_dir():
         if not args.allow_missing:
@@ -185,26 +217,27 @@ def main():
             return 2
         print(f"WARNING: {todo_dir} does not exist; treating as empty (--allow-missing).", file=sys.stderr)
 
-    raw_ids, numeric_ids = collect_ids(todo_dir)
+    raw_ids, numeric_ids = collect_ids(todo_dir, finished_dir)
 
     if args.check is not None:
         normalized = normalize_check_id(args.check)
         if normalized is None:
-            print(f"ERROR: '{args.check}' is not a valid id (expected e.g. '12' or '7a').", file=sys.stderr)
+            example = f"{ID_PROJECT_LETTER}0012" if ID_PROJECT_LETTER else "0001"
+            print(f"ERROR: '{args.check}' is not a valid id (expected e.g. '{example}' or '7a').", file=sys.stderr)
             return 1
         if normalized in raw_ids:
-            print(f"TAKEN: {normalized} is already in use.")
+            print(f"TAKEN: {format_id(normalized)} is already in use.")
             return 1
-        print(f"FREE: {normalized} is not currently in use.")
+        print(f"FREE: {format_id(normalized)} is not currently in use.")
         return 0
 
     if args.list:
         for raw_id in sorted(raw_ids, key=sort_key):
-            print(raw_id)
+            print(format_id(raw_id))
         return 0
 
     next_id = 1 + max(numeric_ids, default=0)
-    print(next_id)
+    print(format_id(str(next_id)))
     return 0
 
 
diff --git a/scripts/todo-status-audit.py b/scripts/todo-status-audit.py
index 6b6e37cdbc..cfd88bb47c 100755
--- a/scripts/todo-status-audit.py
+++ b/scripts/todo-status-audit.py
@@ -12,7 +12,7 @@
 # * specific language governing permissions and limitations under the License.
 # ***************************************************************************************************************************
 """
-Best-effort status/header consistency pre-filter for this repository's .work/todo/ plan files.
+Best-effort status/header consistency pre-filter for this project's plan files under ~/Project Work/todos/juneau/.
 
 Repo-agnostic: the repository root is derived from this file's own location
 (<root>/scripts/todo-status-audit.py -> <root>), never hardcoded, so the same body works in
@@ -20,7 +20,7 @@ every repository that adopts the convention. Only the REPO_LABEL / SKILL_NAME co
 below and the license header differ between copies.
 
 Checks every TODO-<id>-*.md / READY-<id>-*.md / MAYBE-<id>-*.md / HOLD-<id>-*.md file directly
-under .work/todo/ (FINISHED-/CANCELLED-*.md archives are explicitly out of scope -- per this
+under ~/Project Work/todos/juneau/ (FINISHED-/CANCELLED-*.md archives are explicitly out of scope -- per this
 repo's TODO-management skill, "status line is not required in FINISHED archives") against that
 skill's "Per-file `Current status:` and `Complexity:` header" rules, and flags candidate
 inconsistencies. This is a PRE-FILTER, not a validator: it flags candidates for a human
@@ -63,12 +63,11 @@ trap as running `rg` over the gitignored .work/ without --no-ignore.
 Usage:
     ./scripts/todo-status-audit.py
     ./scripts/todo-status-audit.py --verbose
-    ./scripts/todo-status-audit.py --root /path/to/other/repo
+    ./scripts/todo-status-audit.py --root ~/Project Work
     ./scripts/todo-status-audit.py --dir /path/to/alternate/todo/dir
 
 Options:
-    --root <path>   Repository root; scans <root>/.work/todo/ (default: parent of this
-                    script's directory). Ignored if --dir is given.
+    --root <path>   Project Work root (default: ~/Project Work). Ignored if --dir is given.
     --dir <path>    Exact directory to scan, overriding --root. Non-recursive -- only *.md
                     files directly in this directory are considered.
     --verbose, -v   Also print files that passed every check (default: only print flagged files).
@@ -92,11 +91,12 @@ from pathlib import Path
 # copy of this script; keep it that way so a fix lands once and is copied verbatim.
 # ---------------------------------------------------------------------------------------
 REPO_LABEL = "Apache Juneau"
-SKILL_NAME = "juneau-todo-management"
+SKILL_NAME = "todo-and-waves"
+TRACKER_SLUG = "juneau"
 
-DEFAULT_REPO_ROOT = Path(__file__).resolve().parent.parent
+PROJECT_WORK = Path.home() / "Project Work"
 
-FILENAME_RE = re.compile(r"^(TODO|READY|MAYBE|HOLD)-\d+[a-z]*-.*\.md$")
+FILENAME_RE = re.compile(r"^(TODO|READY|MAYBE|HOLD)-J\d+[a-z0-9]*-.*\.md$")
 
 STATUS_LINE_RE = re.compile(r"^\s*Current status:\s*(.*)$", re.IGNORECASE | re.MULTILINE)
 COMPLEXITY_LINE_RE = re.compile(r"^\s*Complexity:\s*(.*)$", re.IGNORECASE | re.MULTILINE)
@@ -224,11 +224,11 @@ def audit_file(path: Path) -> list:
 
 def main() -> int:
     parser = argparse.ArgumentParser(
-        description=f"Best-effort pre-filter for {REPO_LABEL}'s .work/todo/ header inconsistencies (see @{SKILL_NAME}).",
+        description=f"Best-effort pre-filter for {REPO_LABEL} tracker header inconsistencies (see @{SKILL_NAME}).",
         epilog=__doc__,
         formatter_class=argparse.RawDescriptionHelpFormatter,
     )
-    parser.add_argument("--root", metavar="PATH", help="Repository root; scans <root>/.work/todo/ (default: parent of this script's directory).")
+    parser.add_argument("--root", metavar="PATH", help="Project Work root (default: ~/Project Work).")
     parser.add_argument("--dir", metavar="PATH", help="Exact directory to scan, overriding --root.")
     parser.add_argument("--verbose", "-v", action="store_true", help="Also print files that passed every check.")
     args = parser.parse_args()
@@ -236,8 +236,8 @@ def main() -> int:
     if args.dir:
         todo_dir = Path(args.dir).resolve()
     else:
-        repo_root = Path(args.root).resolve() if args.root else DEFAULT_REPO_ROOT
-        todo_dir = repo_root / ".work" / "todo"
+        project_work = Path(args.root).expanduser().resolve() if args.root else PROJECT_WORK
+        todo_dir = project_work / "todos" / TRACKER_SLUG
 
     # Always announce the tree actually scanned, for the same reason todo-next-id.py does:
     # bare per-repository ids make a wrong-tree run indistinguishable from a right-tree one.