Skip to content

Commit dedbea0

Browse files
committed
.spec-driver
1 parent 80fd838 commit dedbea0

24 files changed

Lines changed: 555 additions & 76 deletions

File tree

.contracts/all/supekku/cli/edit.py.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,17 @@ Returns normally on success.
1717
IMPORTANT: typer.Exit inherits from RuntimeError. Callers with
1818
``except RuntimeError`` MUST guard with ``except typer.Exit: raise``
1919
first, or use an early ``return`` after this call.
20+
- `_verify_memory(memory_id, path) -> None`: Stamp verification SHA and dates on a memory artifact.
21+
22+
Raises typer.Exit(EXIT_FAILURE) if git is unavailable.
2023
- @app.command(adr) `edit_adr(decision_id, status, root) -> None`: Edit ADR in editor.
2124
- @app.command(audit) `edit_audit(audit_id, status, root) -> None`: Edit audit in editor.
2225
- @app.command(card) `edit_card(card_id, status, anywhere, root) -> None`: Edit card in editor.
2326
- @app.command(delta) `edit_delta(delta_id, status, root) -> None`: Edit delta in editor.
2427
- @app.command(drift) `edit_drift(ledger_id, status, root) -> None`: Edit drift ledger in editor.
2528
- @app.command(improvement) `edit_improvement(improvement_id, status, root) -> None`: Edit improvement in editor.
2629
- @app.command(issue) `edit_issue(issue_id, status, root) -> None`: Edit issue in editor.
27-
- @app.command(memory) `edit_memory(memory_id, status, root) -> None`: Edit memory record in editor.
30+
- @app.command(memory) `edit_memory(memory_id, status, verify, root) -> None`: Edit memory record in editor.
2831
- @app.command(plan) `edit_plan(plan_id, status, root) -> None`: Edit implementation plan in editor.
2932
- @app.command(policy) `edit_policy(policy_id, status, root) -> None`: Edit policy in editor.
3033
- @app.command(problem) `edit_problem(problem_id, status, root) -> None`: Edit problem in editor.

.contracts/all/supekku/cli/list.py.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ Display formatting is delegated to supekku.scripts.lib.formatters
1212

1313
## Functions
1414

15+
- `_format_stale_memories(records, root) -> str`: Compute staleness and format as tiered table.
1516
- `_parse_relation_filter(value) -> tuple[Tuple[str, str]]`: Parse ``TYPE:TARGET`` from ``--relation`` flag.
1617

1718
Splits on the first colon. Raises :class:`typer.BadParameter` if no colon
@@ -77,7 +78,7 @@ By default, resolved/implemented items are excluded. Use --all to show all.
7778
Shortcut for: list backlog --kind issue
7879

7980
By default, resolved/implemented items are excluded. Use --all to show all.
80-
- @app.command(memories) `list_memories(root, status, memory_type, tag, path, command, match_tag, include_draft, limit, substring, regexp, case_insensitive, format_type, json_output, links_to, truncate) -> None`: List memory records with optional filtering and scope matching.
81+
- @app.command(memories) `list_memories(root, status, memory_type, tag, path, command, match_tag, include_draft, limit, substring, regexp, case_insensitive, format_type, json_output, links_to, truncate, stale) -> None`: List memory records with optional filtering and scope matching.
8182

8283
The --filter flag does substring matching (case-insensitive).
8384
Metadata pre-filters (--type, --status, --tag) apply first (AND logic).

.contracts/all/supekku/scripts/lib/formatters/memory_formatters.py.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,11 @@ Memory display formatters.
55
Pure formatting functions with no business logic.
66
Formatters take MemoryRecord objects and return formatted strings for display.
77

8+
## Constants
9+
10+
- `_STALENESS_HEADER`
11+
- `_TIER_LABELS`
12+
813
## Functions
914

1015
- `_calculate_column_widths(terminal_width) -> dict[Tuple[int, int]]`: Calculate column widths for memory table based on terminal width.
@@ -15,6 +20,10 @@ Formatters take MemoryRecord objects and return formatted strings for display.
1520
- `_format_provenance(provenance) -> list[str]`: Format provenance dict as indented sub-lines.
1621
- `_format_relations(relations) -> list[str]`: Format relations list as indented entries.
1722
- `_format_scope(scope) -> list[str]`: Format scope dict as indented sub-lines.
23+
- `_format_scope_cell(info) -> str`: Format the scope summary cell.
24+
- `_format_stale_cell(info) -> str`: Format the staleness indicator cell.
25+
- `_format_staleness_row(info, records) -> str`: Format a single staleness row.
26+
- `_partition_tiers(infos) -> tuple[Tuple[list[StalenessInfo], list[StalenessInfo], list[StalenessInfo]]]`: Split staleness infos into three tiers.
1827
- `_prepare_memory_row(record) -> list[str]`: Prepare a single row for the memory table.
1928
- `_prepare_memory_tsv_row(record) -> list[str]`: Prepare a single memory record as a plain TSV row (no markup).
2029
- `format_link_graph_json(nodes) -> str`: Format link graph nodes as JSON array.
@@ -65,3 +74,18 @@ Args:
6574

6675
Returns:
6776
Formatted string in requested format.
77+
- `format_staleness_table(infos, records) -> str`: Format staleness info as a three-tier plain-text table.
78+
79+
Tiers:
80+
1. Scoped + attested — sorted by commits_since descending
81+
2. Scoped + unattested — sorted by days_since descending
82+
3. Unscoped — sorted by days_since descending
83+
84+
Empty tiers are omitted.
85+
86+
Args:
87+
infos: StalenessInfo list from compute_batch_staleness.
88+
records: Mapping of memory_id → MemoryRecord for metadata.
89+
90+
Returns:
91+
Formatted multi-tier string, or empty string if no infos.
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
# supekku.scripts.lib.memory.staleness
2+
3+
Batched staleness computation for memory artifacts.
4+
5+
Computes staleness by counting git commits that touched scoped paths
6+
since a memory's last verified SHA. Uses a single git invocation for
7+
all scoped memories (DEC-086-06).
8+
9+
## Constants
10+
11+
- `__all__`
12+
13+
## Functions
14+
15+
- `_assign_commit_counts(results, attested, commit_data) -> None`: Count commits affecting each attested memory's scope paths.
16+
- `_collect_all_pathspecs(attested) -> list[str]`: Collect deduplicated pathspecs from all attested records.
17+
- `_collect_scope_paths(record) -> list[str]`: Collect all scope paths and converted globs for a record.
18+
- `_days_since(record, today) -> <BinOp>`: Compute days since the most relevant date on a record.
19+
- `_find_oldest_sha(attested) -> str`: Find the verified_sha from the record with the oldest verified date.
20+
- `_parse_git_log_output(output) -> list[_CommitEntry]`: Parse ``git log --oneline --name-only`` output into commit entries.
21+
- `_path_matches_scope(file_path, scope_paths) -> bool`: Check whether a file path matches any scope path (prefix match).
22+
- `_query_git_log(attested, root) -> <BinOp>`: Run a single git log and parse commits with affected paths.
23+
24+
Returns None if git is unavailable or the command fails, so callers
25+
can distinguish "no commits found" from "unable to query."
26+
- `compute_batch_staleness(records, root) -> list[StalenessInfo]`: Compute staleness for multiple memories using a single git invocation.
27+
28+
For scoped+attested memories, runs one ``git log`` from the oldest
29+
verified SHA and counts commits per memory's scope paths.
30+
31+
Unscoped and unattested memories fall back to ``days_since`` from
32+
their verified or updated date.
33+
34+
Args:
35+
records: Memory records to evaluate.
36+
root: Repository root for git commands.
37+
38+
Returns:
39+
StalenessInfo for each input record, in the same order.
40+
- `glob_to_pathspec(glob) -> str`: Convert a scope glob pattern to a git pathspec.
41+
42+
Strips trailing ``/**`` (directory wildcard) to produce a directory
43+
prefix that git understands. Other patterns pass through as-is.
44+
Leading ``./`` is also stripped.
45+
46+
Args:
47+
glob: Scope glob pattern (e.g. ``supekku/cli/**``).
48+
49+
Returns:
50+
Git-compatible pathspec string.
51+
52+
## Classes
53+
54+
### StalenessInfo
55+
56+
Staleness data for a single memory.
57+
58+
### _CommitEntry
59+
60+
A parsed commit from git log output.

.contracts/all/supekku/scripts/lib/skills/sync.py.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# supekku.scripts.lib.skills.sync
22

3-
Allowlist-driven skills sync: install, prune, and expose skills in AGENTS.md.
3+
Allowlist-driven skills install: install, prune, and expose skills in AGENTS.md.
44

55
Reads `.spec-driver/skills.allowlist`, installs allowlisted skills from the
66
package source (`supekku/skills/`) to `.spec-driver/skills/` (the canonical

.contracts/public/supekku/cli/edit.py.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ Edit commands for opening artifacts in an editor or updating status.
1616
- @app.command(drift) `edit_drift(ledger_id, status, root) -> None`: Edit drift ledger in editor.
1717
- @app.command(improvement) `edit_improvement(improvement_id, status, root) -> None`: Edit improvement in editor.
1818
- @app.command(issue) `edit_issue(issue_id, status, root) -> None`: Edit issue in editor.
19-
- @app.command(memory) `edit_memory(memory_id, status, root) -> None`: Edit memory record in editor.
19+
- @app.command(memory) `edit_memory(memory_id, status, verify, root) -> None`: Edit memory record in editor.
2020
- @app.command(plan) `edit_plan(plan_id, status, root) -> None`: Edit implementation plan in editor.
2121
- @app.command(policy) `edit_policy(policy_id, status, root) -> None`: Edit policy in editor.
2222
- @app.command(problem) `edit_problem(problem_id, status, root) -> None`: Edit problem in editor.

.contracts/public/supekku/cli/list.py.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ By default, resolved/implemented items are excluded. Use --all to show all.
7272
Shortcut for: list backlog --kind issue
7373

7474
By default, resolved/implemented items are excluded. Use --all to show all.
75-
- @app.command(memories) `list_memories(root, status, memory_type, tag, path, command, match_tag, include_draft, limit, substring, regexp, case_insensitive, format_type, json_output, links_to, truncate) -> None`: List memory records with optional filtering and scope matching.
75+
- @app.command(memories) `list_memories(root, status, memory_type, tag, path, command, match_tag, include_draft, limit, substring, regexp, case_insensitive, format_type, json_output, links_to, truncate, stale) -> None`: List memory records with optional filtering and scope matching.
7676

7777
The --filter flag does substring matching (case-insensitive).
7878
Metadata pre-filters (--type, --status, --tag) apply first (AND logic).

.contracts/public/supekku/scripts/lib/formatters/memory_formatters.py.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,3 +55,18 @@ Args:
5555

5656
Returns:
5757
Formatted string in requested format.
58+
- `format_staleness_table(infos, records) -> str`: Format staleness info as a three-tier plain-text table.
59+
60+
Tiers:
61+
1. Scoped + attested — sorted by commits_since descending
62+
2. Scoped + unattested — sorted by days_since descending
63+
3. Unscoped — sorted by days_since descending
64+
65+
Empty tiers are omitted.
66+
67+
Args:
68+
infos: StalenessInfo list from compute_batch_staleness.
69+
records: Mapping of memory_id → MemoryRecord for metadata.
70+
71+
Returns:
72+
Formatted multi-tier string, or empty string if no infos.
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
# supekku.scripts.lib.memory.staleness
2+
3+
Batched staleness computation for memory artifacts.
4+
5+
Computes staleness by counting git commits that touched scoped paths
6+
since a memory's last verified SHA. Uses a single git invocation for
7+
all scoped memories (DEC-086-06).
8+
9+
## Functions
10+
11+
- `compute_batch_staleness(records, root) -> list[StalenessInfo]`: Compute staleness for multiple memories using a single git invocation.
12+
13+
For scoped+attested memories, runs one ``git log`` from the oldest
14+
verified SHA and counts commits per memory's scope paths.
15+
16+
Unscoped and unattested memories fall back to ``days_since`` from
17+
their verified or updated date.
18+
19+
Args:
20+
records: Memory records to evaluate.
21+
root: Repository root for git commands.
22+
23+
Returns:
24+
StalenessInfo for each input record, in the same order.
25+
- `glob_to_pathspec(glob) -> str`: Convert a scope glob pattern to a git pathspec.
26+
27+
Strips trailing ``/**`` (directory wildcard) to produce a directory
28+
prefix that git understands. Other patterns pass through as-is.
29+
Leading ``./`` is also stripped.
30+
31+
Args:
32+
glob: Scope glob pattern (e.g. ``supekku/cli/**``).
33+
34+
Returns:
35+
Git-compatible pathspec string.
36+
37+
## Classes
38+
39+
### StalenessInfo
40+
41+
Staleness data for a single memory.

.contracts/public/supekku/scripts/lib/skills/sync.py.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# supekku.scripts.lib.skills.sync
22

3-
Allowlist-driven skills sync: install, prune, and expose skills in AGENTS.md.
3+
Allowlist-driven skills install: install, prune, and expose skills in AGENTS.md.
44

55
Reads `.spec-driver/skills.allowlist`, installs allowlisted skills from the
66
package source (`supekku/skills/`) to `.spec-driver/skills/` (the canonical

0 commit comments

Comments
 (0)