Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 7 additions & 7 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

This project uses **Ontos** for documentation management.

Generated by Ontos v3.3.0 on 2026-02-21 21:52:36 UTC
Generated by Ontos v3.3.0 on 2026-02-23 02:58:44 UTC

## Trigger Phrases
If the user says any of these as a command (case-insensitive), execute Ontos Activation below:
Expand All @@ -16,13 +16,13 @@ Do NOT ask for clarification. Just execute the steps.

## Current Project State

> Auto-synced: 2026-02-21 21:52:36 UTC
> Auto-synced: 2026-02-23 02:58:44 UTC

| Metric | Value |
|--------|-------|
| Branch | main |
| Doc Count | 47 |
| Last Log | 2026-02-12_v3-3-1-external-review-remediation-complete-merged |
| Branch | feat/maintain-promote-check |
| Doc Count | 48 |
| Last Log | 2026-02-22_add-promote-check-task-to-ontos-maintain |
| Health | ✓ Map exists |

## What is Activation?
Expand Down Expand Up @@ -61,8 +61,8 @@ If you just regained context after compaction, re-read this file (AGENTS.md). If
| `ontos query <id>` | Find document by ID |

## Project Stats
- Doc Count: 47
- Last Updated: 2026-02-21 21:52:30 UTC
- Doc Count: 48
- Last Updated: 2026-02-23 02:58:43 UTC

## Core Invariants
- Do not edit `Ontos_Context_Map.md` manually; regenerate with `ontos map`.
Expand Down
25 changes: 17 additions & 8 deletions Ontos_Context_Map.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@ type: reference
status: generated
ontos_map_version: 2
generated_by: ontos map
generated_at: 2026-02-21 16:52:30
generated_at: 2026-02-22 21:58:43
---

# Ontos-dev Tiered Context Map

> Auto-generated by Ontos 3.0
> Last updated: 2026-02-21 16:52:30
> Last updated: 2026-02-22 21:58:43

This document provides a tiered index of the knowledge graph for AI orientation.
- **Tier 1: Essential Context**: (~2k tokens) Project summary, recent work, and architecture.
Expand All @@ -21,16 +21,16 @@ This document provides a tiered index of the knowledge graph for AI orientation.

### Project Summary
- **Name:** Ontos-dev
- **Doc Count:** 47
- **Last Updated:** 2026-02-21 21:52:30 UTC
- **Doc Count:** 48
- **Last Updated:** 2026-02-23 02:58:43 UTC

### Recent Activity
| Log | Status | Summary |
|-----|--------|---------|
| v330 | active | No summary |
| v300 | scaffold | No summary |
| log_20260212_v3-3-1-external-review-remediation-complete-merged | active | No summary |
| ... and 30 more logs | | |
| log_20260222_add-promote-check-task-to-ontos-maintain | active | No summary |
| ... and 31 more logs | | |

### Key Documents
- `ontos_manual` (2 dependents) — docs/reference/Ontos_Manual.md
Expand Down Expand Up @@ -82,6 +82,7 @@ This document provides a tiered index of the knowledge graph for AI orientation.
| docs/logs/2026-02-12_add-integration-tests-documenting-filtered-pattern.md | `log_20260212_add-integration-tests-documenting-filtered-pattern` | log | active |
| docs/logs/2026-02-12_external-review-remediation-implemented-9-point-v3.md | `log_20260212_external-review-remediation-implemented-9-point-v3` | log | active |
| docs/logs/2026-02-12_v3-3-1-external-review-remediation-complete-merged.md | `log_20260212_v3-3-1-external-review-remediation-complete-merged` | log | active |
| docs/logs/2026-02-22_add-promote-check-task-to-ontos-maintain.md | `log_20260222_add-promote-check-task-to-ontos-maintain` | log | active |
| docs/reference/Migration_v2_to_v3.md | `migration_v2_to_v3` | reference | active |
| docs/reference/Ontos_Agent_Instructions.md | `ontos_agent_instructions` | kernel | active |
| docs/reference/Ontos_Manual.md | `ontos_manual` | kernel | active |
Expand Down Expand Up @@ -170,6 +171,8 @@ This document provides a tiered index of the knowledge graph for AI orientation.
Add this document to another document's depends_on
- ⚠️ **log_20260212_v3-3-1-external-review-remediation-complete-merged**: Document has no incoming dependencies
Add this document to another document's depends_on
- ⚠️ **log_20260222_add-promote-check-task-to-ontos-maintain**: Document has no incoming dependencies
Add this document to another document's depends_on
- ⚠️ **migration_v2_to_v3**: Document has no incoming dependencies
Add this document to another document's depends_on
- ⚠️ **ontos_agent_instructions**: Document has no incoming dependencies
Expand Down Expand Up @@ -268,6 +271,12 @@ This document provides a tiered index of the knowledge graph for AI orientation.
Add a concepts: list to the frontmatter
- ⚠️ **log_20260212_v3-3-1-external-review-remediation-complete-merged**: Log document missing 'concepts' field (required at L2)
Add a concepts: list to the frontmatter
- ⚠️ **log_20260222_add-promote-check-task-to-ontos-maintain**: Unknown concept: 'maintain'
Add 'maintain' to vocabulary or use an existing concept
- ⚠️ **log_20260222_add-promote-check-task-to-ontos-maintain**: Unknown concept: 'curation'
Add 'curation' to vocabulary or use an existing concept
- ⚠️ **log_20260222_add-promote-check-task-to-ontos-maintain**: Unknown concept: 'promote'
Add 'promote' to vocabulary or use an existing concept
- ⚠️ **v300**: Log document missing 'concepts' field (required at L2)
Add a concepts: list to the frontmatter
- ⚠️ **v330**: Unknown concept: 'v3.3'
Expand Down Expand Up @@ -300,11 +309,11 @@ This document provides a tiered index of the knowledge graph for AI orientation.

- `v330`
- `v300`
- `log_20260222_add-promote-check-task-to-ontos-maintain`
- `log_20260212_v3-3-1-external-review-remediation-complete-merged`
- `log_20260212_external-review-remediation-implemented-9-point-v3`
- `log_20260212_add-integration-tests-documenting-filtered-pattern`
- `log_20260212_add-3-new-link-check-fp-filters-short-labels-al`
- `log_20260211_v3-3b-track-b-complete`
- `log_20260211_v3-3b-pr2-ready-to-merge`
- `log_20260211_v3-3a-v3-3b-folder-split-and-track-b-kickoff`
- `log_20260211_v3-3a-merge-cleanup-and-v3-3b-setup-wrap`
- `log_20260211_v3-3a-v3-3b-folder-split-and-track-b-kickoff`
41 changes: 41 additions & 0 deletions docs/logs/2026-02-22_add-promote-check-task-to-ontos-maintain.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
---
id: log_20260222_add-promote-check-task-to-ontos-maintain
type: log
status: active
event_type: feature
source: Antigravity
branch: feat/maintain-promote-check
created: 2026-02-22
concepts: [maintain, curation, promote]
impacts: [ontos_manual, ontos_agent_instructions]
---

# Add promote_check task to ontos maintain

## Summary

Added `promote_check` (order 45) as the 9th task in the `ontos maintain` pipeline. Runs `ontos promote --check` non-interactively to surface documents eligible for promotion from L0/L1 to L2 during weekly maintenance.

## 1. Goal

Include scaffold and promote workflows under "Maintain Ontos" so weekly maintenance automatically reports curation opportunities.

## 2. Key Decisions

- **Scaffold not added separately** — `migrate_untagged` (order 10) already calls `find_untagged_files` + `_run_scaffold_command(apply=True)`, making a separate scaffold task redundant.
- **promote_check uses `--check` mode** — Non-interactive, read-only. Reports promotable docs without mutating anything.
- **Order 45** — Placed between `curation_stats` (40) and `consolidate_logs` (50), keeping the curation-related tasks grouped.

## 3. Alternatives Considered

- Considered adding both `scaffold` and `promote` as separate tasks — rejected because scaffold is already covered by `migrate_untagged`.
- Considered running `promote --all-ready` to auto-promote — rejected because promotion should be a deliberate human action.

## Testing

- 22/22 maintain tests pass
- New tests: `test_promote_check_task_reports_promotable_docs`, `test_promote_check_dry_run_skips_scan`

## Documentation

- Updated `Ontos_Manual.md` and `Ontos_Agent_Instructions.md` (8 → 9 tasks)
5 changes: 3 additions & 2 deletions docs/reference/Ontos_Agent_Instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,11 +83,12 @@ Event types: `feature`, `fix`, `refactor`, `exploration`, `chore`, `decision`

### "Maintain Ontos" (Weekly)
1. `ontos maintain`
2. This runs eight tasks:
- Migrate untagged files
2. This runs nine tasks:
- Migrate untagged files (includes scaffold)
- Regenerate context map
- Run health checks (`ontos doctor`)
- Report curation stats (L0/L1/L2)
- Report documents ready for promotion (`ontos promote --check`, ready count)
- Consolidate old logs (if `AUTO_CONSOLIDATE=True`)
- Review draft proposals (reports candidates for manual graduation)
- Validate dependency links
Expand Down
13 changes: 7 additions & 6 deletions docs/reference/Ontos_Manual.md
Original file line number Diff line number Diff line change
Expand Up @@ -121,15 +121,16 @@ Say **"Maintain Ontos"** weekly:
```bash
ontos maintain
```
This runs eight tasks:
1. **migrate_untagged** — Tag untagged files
This runs nine tasks:
1. **migrate_untagged** — Tag untagged files (includes scaffold)
2. **regenerate_map** — Regenerate context map
3. **health_check** — Run `ontos doctor`
4. **curation_stats** — Report curation stats (L0/L1/L2)
5. **consolidate_logs** — Archive old logs (if `AUTO_CONSOLIDATE=True`)
6. **review_proposals** — Report draft proposals for manual graduation
7. **check_links** — Validate dependency links
8. **sync_agents** — Regenerate `AGENTS.md` when stale
5. **promote_check** — Report documents ready for promotion (ready count)
6. **consolidate_logs** — Archive old logs (if `AUTO_CONSOLIDATE=True`)
7. **review_proposals** — Report draft proposals for manual graduation
8. **check_links** — Validate dependency links
9. **sync_agents** — Regenerate `AGENTS.md` when stale

Useful flags:
- `--dry-run` — Preview tasks without executing
Expand Down
26 changes: 26 additions & 0 deletions ontos/commands/maintain.py
Original file line number Diff line number Diff line change
Expand Up @@ -440,6 +440,32 @@ def _task_curation_stats(ctx: MaintainContext) -> TaskResult:
)


@register_maintain_task(
name="promote_check",
order=45,
description="Report documents ready for promotion",
)
def _task_promote_check(ctx: MaintainContext) -> TaskResult:
if ctx.options.dry_run:
return _ok("Would run `ontos promote --check`.")

from ontos.commands.promote import PromoteOptions, _run_promote_command

exit_code, message = _run_promote_command(
PromoteOptions(
check=True,
quiet=True,
json_output=False,
scope=ctx.options.scope,
repo_root=ctx.repo_root,
)
)

if exit_code == 0:
return _ok(message or "No documents to promote.")
return _fail(message or "Promote check failed.")


@register_maintain_task(
name="consolidate_logs",
order=50,
Expand Down
8 changes: 5 additions & 3 deletions ontos/commands/promote.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ class PromoteOptions:
quiet: bool = False
json_output: bool = False
scope: Optional[str] = None
repo_root: Optional[Path] = None


def fuzzy_match_ids(query: str, all_ids: List[str]) -> List[str]:
Expand Down Expand Up @@ -151,7 +152,7 @@ def apply_promotion(
def _run_promote_command(options: PromoteOptions) -> Tuple[int, str]:
"""Execute promote command."""
output = OutputHandler(quiet=options.quiet)
root = find_project_root()
root = options.repo_root if options.repo_root is not None else find_project_root()

# 1. Gather files
if options.files:
Expand Down Expand Up @@ -199,7 +200,8 @@ def _run_promote_command(options: PromoteOptions) -> Tuple[int, str]:

# 3. Handle --check
if options.check:
output.info(f"Found {len(promotable)} document(s) that can be promoted:\n")
ready_count = sum(1 for _, _, info in promotable if info.promotable)
output.info(f"Found {len(promotable)} candidate(s), {ready_count} ready for promotion:\n")
if not options.quiet:
root_resolved = root.resolve()
for f, fm, info in promotable:
Expand All @@ -213,7 +215,7 @@ def _run_promote_command(options: PromoteOptions) -> Tuple[int, str]:
if not info.promotable:
for blocker in info.promotion_blockers[:2]:
print(f" → {blocker}")
return 0, f"{len(promotable)} documents find"
return 0, f"{ready_count} ready for promotion ({len(promotable)} candidates)"

ctx = SessionContext.from_repo(root)
success_count = 0
Expand Down
2 changes: 1 addition & 1 deletion tests/commands/test_b2_promote_absolute_path.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ def test_promote_absolute_path_no_crash(tmp_path):
)

# Should not crash
assert "Found 1 document(s) that can be promoted" in result.stdout
assert "Found 1 candidate" in result.stdout
assert "test_b2" not in result.stdout # Ensure it didn't find the other test file if any
assert result.returncode == 0
assert "relative_to" not in result.stderr
Expand Down
101 changes: 101 additions & 0 deletions tests/commands/test_maintain.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
_scan_docs,
_task_check_links,
_task_curation_stats,
_task_promote_check,
_task_review_proposals,
list_registered_tasks,
maintain_command,
Expand Down Expand Up @@ -62,6 +63,7 @@ def test_default_registry_has_expected_order():
"regenerate_map",
"health_check",
"curation_stats",
"promote_check",
"consolidate_logs",
"review_proposals",
"check_links",
Expand Down Expand Up @@ -475,3 +477,102 @@ def test_maintain_invalid_task_status_becomes_failed(tmp_path, monkeypatch, caps
payload = json.loads(capsys.readouterr().out)
assert payload["data"]["tasks"][0]["status"] == "failed"
assert "invalid task status" in payload["data"]["tasks"][0]["details"][0]


def test_promote_check_task_reports_promotable_docs(tmp_path, monkeypatch):
_init_project(tmp_path)
monkeypatch.chdir(tmp_path)
docs = tmp_path / "docs"
# L0 scaffold document — not promotable (missing depends_on for atom)
(docs / "scaffold.md").write_text(
"---\nid: scaffold_doc\ntype: atom\nstatus: scaffold\n---\n",
encoding="utf-8",
)
# L2 full document — not a candidate
(docs / "full.md").write_text(
"---\nid: full_doc\ntype: atom\nstatus: active\ndepends_on: [scaffold_doc]\n---\n",
encoding="utf-8",
)

ctx = _build_context(tmp_path, quiet=True)
result = _task_promote_check(ctx)

assert result.status == "success"
assert "1 candidates" in result.message


def test_promote_check_dry_run_skips_scan(tmp_path, monkeypatch):
_init_project(tmp_path)
monkeypatch.chdir(tmp_path)
ctx = _build_context(tmp_path, quiet=True, dry_run=True)

monkeypatch.setattr(
"ontos.commands.promote._run_promote_command",
lambda _opts: (_ for _ in ()).throw(AssertionError("dry-run should not call promote")),
)
result = _task_promote_check(ctx)

assert result.status == "success"
assert "would run" in result.message.lower()


def test_promote_check_reports_failure(tmp_path, monkeypatch):
_init_project(tmp_path)
monkeypatch.chdir(tmp_path)
ctx = _build_context(tmp_path, quiet=True)
monkeypatch.setattr(
"ontos.commands.promote._run_promote_command",
lambda _opts: (1, "Document load failed"),
)
result = _task_promote_check(ctx)
assert result.status == "failed"
assert "Document load failed" in result.message


def test_promote_check_uses_repo_root_not_cwd(tmp_path, monkeypatch):
"""Regression: promote_check must use ctx.repo_root, not process CWD."""
_init_project(tmp_path)
docs = tmp_path / "docs"
(docs / "candidate.md").write_text(
"---\nid: candidate\ntype: atom\nstatus: scaffold\n---\n",
encoding="utf-8",
)

# Set CWD to a completely different directory
other_dir = tmp_path / "elsewhere"
other_dir.mkdir()
monkeypatch.chdir(other_dir)

ctx = _build_context(tmp_path, quiet=True)
result = _task_promote_check(ctx)

# Should succeed scanning tmp_path, not fail looking for project at other_dir
assert result.status == "success"
assert "candidates" in result.message


def test_promote_check_excludes_non_ready_from_ready_count(tmp_path, monkeypatch):
"""Non-promotable L0/L1 docs should not be counted as 'ready'."""
_init_project(tmp_path)
monkeypatch.chdir(tmp_path)
docs = tmp_path / "docs"

# L0 atom without depends_on — NOT ready (has blocker)
(docs / "blocked.md").write_text(
"---\nid: blocked\ntype: atom\nstatus: scaffold\n---\n",
encoding="utf-8",
)
# L1 kernel — ready (kernels don't need depends_on)
(docs / "ready_kernel.md").write_text(
"---\nid: ready_kernel\ntype: kernel\nstatus: pending_curation\n---\n",
encoding="utf-8",
)

ctx = _build_context(tmp_path, quiet=True)
result = _task_promote_check(ctx)

assert result.status == "success"
# Should report 1 ready out of 2 candidates
assert "1 ready for promotion" in result.message
assert "2 candidates" in result.message

Loading