Compare commits
71 Commits
testdrive-
...
v0.11.0
| Author | SHA1 | Date | |
|---|---|---|---|
| 1f9d618777 | |||
| ce11c03326 | |||
| 0ade4798f3 | |||
| 843f579305 | |||
| 7515b9c0e5 | |||
| 7f696582a9 | |||
| 5fea98b068 | |||
| 0b5098370a | |||
| 599de22f59 | |||
| 23521ad6ae | |||
| 0d276e8589 | |||
| 587d2f5889 | |||
| bf4767d06b | |||
| 75c8f8c325 | |||
| 6852ad915e | |||
| c4ee5cc645 | |||
| 061ba88206 | |||
| 4e9117ddcb | |||
| 5e3646fdff | |||
| fc828a345b | |||
| 4d72ee8032 | |||
| 689fb21774 | |||
| 20c0cfece7 | |||
| 0d78837a53 | |||
| 2836ae14de | |||
| 5264a6083c | |||
| a969c5de47 | |||
| f27eea6b5b | |||
| ae2e8ee4a7 | |||
| b10d2fd3d0 | |||
| 92719ff424 | |||
| 9026646594 | |||
| 77415bfad7 | |||
| 5e147865f8 | |||
| 3003b9b8da | |||
| d32dc41315 | |||
| f19a88f1d5 | |||
| 7d115b6325 | |||
| 60d9f7a2c3 | |||
| f3aaec99bb | |||
| b81ce5631d | |||
| 14108533fb | |||
| b6f95066a3 | |||
| 6df9b5df05 | |||
| 82c1a3ab65 | |||
| da34303057 | |||
| d2cd2d22fd | |||
| 48e0b60be5 | |||
| 2b35fcde62 | |||
| c46d9f7a0b | |||
| 2b687a4ca8 | |||
| d68e762612 | |||
| b51999582e | |||
| b4157da3dd | |||
| 916c09a22b | |||
| 4d899d0690 | |||
| dcb51b7e3a | |||
| d0432dbe0d | |||
| 45e4c7a6e9 | |||
| 01e5c811ab | |||
| 9fe2960842 | |||
| 7be37df3e4 | |||
| 21189f7664 | |||
| ddd8189576 | |||
| 2e6f292e48 | |||
| a1476a98b5 | |||
| 304959b3ee | |||
| 83086b3773 | |||
| 82eef76366 | |||
| 2838135450 | |||
| d592c5b8b3 |
323
.claude/capabilities/issue-facade.md
Normal file
323
.claude/capabilities/issue-facade.md
Normal file
@@ -0,0 +1,323 @@
|
||||
# Issue Facade - Agent Integration Context
|
||||
|
||||
**🤖 For Coding Agents: Read this to understand how to use issue tracking in this project.**
|
||||
|
||||
## Critical: DO NOT Bypass This Capability
|
||||
|
||||
⚠️ **IMPORTANT:** If you need to work with issues, **you MUST use this capability**. Do NOT:
|
||||
- ❌ Make direct API calls to Gitea/GitHub/GitLab
|
||||
- ❌ Use platform CLIs (gh, glab, etc.)
|
||||
- ❌ Import platform libraries (PyGithub, python-gitlab, etc.)
|
||||
- ❌ Parse HTML/scrape issue tracker web UIs
|
||||
|
||||
**Why?** Bypassing this capability causes:
|
||||
- Credential management chaos (tokens scattered everywhere)
|
||||
- Inconsistent issue state across agents
|
||||
- Massive token waste (redundant API calls)
|
||||
- Platform lock-in (can't switch Gitea → GitHub easily)
|
||||
- Race conditions in multi-agent scenarios
|
||||
|
||||
## Quick Reference
|
||||
|
||||
### Check if Capability is Available
|
||||
|
||||
```bash
|
||||
# Verify installation
|
||||
issue --version
|
||||
# or
|
||||
python -c "from issue_tracker.backends.gitea import GiteaBackend; print('OK')"
|
||||
```
|
||||
|
||||
### Basic Usage (Python)
|
||||
|
||||
```python
|
||||
from issue_tracker.backends.gitea import GiteaBackend
|
||||
from issue_tracker.core.models import Issue, Label, IssueState, User, Comment
|
||||
from issue_tracker.core.interfaces import IssueFilter
|
||||
from datetime import datetime, timezone
|
||||
import os
|
||||
|
||||
# Connect (assumes backend is configured)
|
||||
backend = GiteaBackend()
|
||||
backend.connect({
|
||||
'base_url': os.environ['GITEA_URL'],
|
||||
'token': os.environ['GITEA_API_TOKEN'],
|
||||
'owner': os.environ['GITEA_OWNER'],
|
||||
'repo': os.environ['GITEA_REPO']
|
||||
})
|
||||
|
||||
# List issues for me
|
||||
my_issues = backend.list_issues(IssueFilter(
|
||||
state='open',
|
||||
assignee='my-agent-id',
|
||||
labels=['needs-implementation']
|
||||
))
|
||||
|
||||
# Create issue
|
||||
new_issue = Issue(
|
||||
id=None, number=0,
|
||||
title="Implement feature X",
|
||||
description="Details...",
|
||||
state=IssueState.OPEN,
|
||||
created_at=datetime.now(timezone.utc),
|
||||
updated_at=datetime.now(timezone.utc),
|
||||
labels=[Label(name="feature"), Label(name="priority:high")]
|
||||
)
|
||||
created = backend.create_issue(new_issue)
|
||||
|
||||
# Update issue
|
||||
created.state = IssueState.IN_PROGRESS
|
||||
created.assignees = [User(id="agent-id", username="agent-id")]
|
||||
backend.update_issue(created)
|
||||
|
||||
# Add comment
|
||||
comment = Comment(
|
||||
id=None,
|
||||
body="Implementation started. Working on database schema.",
|
||||
author=User(id="agent-id", username="agent-id"),
|
||||
created_at=datetime.now(timezone.utc)
|
||||
)
|
||||
backend.add_comment(created.id, comment)
|
||||
|
||||
# Close when done
|
||||
created.state = IssueState.CLOSED
|
||||
created.closed_at = datetime.now(timezone.utc)
|
||||
backend.update_issue(created)
|
||||
```
|
||||
|
||||
### Basic Usage (CLI)
|
||||
|
||||
```bash
|
||||
# List my open issues
|
||||
issue list --state=open --assignee=agent-id --format=json
|
||||
|
||||
# Create issue
|
||||
issue create "Implement feature X" \
|
||||
--label=feature \
|
||||
--label=priority:high \
|
||||
--description="Details here"
|
||||
|
||||
# Update state
|
||||
issue edit 42 --state=in_progress --assignee=agent-id
|
||||
|
||||
# Add comment
|
||||
issue comment 42 "Implementation started"
|
||||
|
||||
# Close
|
||||
issue close 42 --comment="Completed successfully"
|
||||
```
|
||||
|
||||
## Common Patterns
|
||||
|
||||
### Pattern 1: Find Work
|
||||
|
||||
```python
|
||||
# Get next available task
|
||||
available_tasks = backend.list_issues(IssueFilter(
|
||||
state='open',
|
||||
labels=['ready', 'needs-implementation']
|
||||
))
|
||||
|
||||
# Filter to unassigned
|
||||
unassigned = [t for t in available_tasks if not t.assignees]
|
||||
|
||||
if unassigned:
|
||||
task = unassigned[0]
|
||||
# Claim it...
|
||||
```
|
||||
|
||||
### Pattern 2: Claim Issue (Prevent Race Conditions)
|
||||
|
||||
```python
|
||||
def claim_issue(issue: Issue, agent_id: str) -> bool:
|
||||
"""Claim an issue safely."""
|
||||
# Check if already claimed
|
||||
if issue.assignees:
|
||||
return False # Already taken
|
||||
|
||||
# Claim it
|
||||
issue.state = IssueState.IN_PROGRESS
|
||||
issue.assignees = [User(id=agent_id, username=agent_id)]
|
||||
backend.update_issue(issue)
|
||||
|
||||
# Announce claim
|
||||
backend.add_comment(issue.id, Comment(
|
||||
id=None,
|
||||
body=f"🤖 Claimed by {agent_id}",
|
||||
author=User(id=agent_id, username=agent_id),
|
||||
created_at=datetime.now(timezone.utc)
|
||||
))
|
||||
return True
|
||||
```
|
||||
|
||||
### Pattern 3: Progress Updates
|
||||
|
||||
```python
|
||||
def report_progress(issue: Issue, message: str, agent_id: str):
|
||||
"""Report progress on an issue."""
|
||||
backend.add_comment(issue.id, Comment(
|
||||
id=None,
|
||||
body=f"**Progress Update:**\n\n{message}",
|
||||
author=User(id=agent_id, username=agent_id),
|
||||
created_at=datetime.now(timezone.utc)
|
||||
))
|
||||
```
|
||||
|
||||
### Pattern 4: Agent-to-Agent Communication
|
||||
|
||||
```python
|
||||
import json
|
||||
|
||||
def post_agent_message(issue_id: str, msg_type: str, data: dict, agent_id: str):
|
||||
"""Post structured message for other agents."""
|
||||
message = {
|
||||
'type': msg_type,
|
||||
'agent': agent_id,
|
||||
'timestamp': datetime.now(timezone.utc).isoformat(),
|
||||
'data': data
|
||||
}
|
||||
backend.add_comment(issue_id, Comment(
|
||||
id=None,
|
||||
body=f"```agent-message\n{json.dumps(message, indent=2)}\n```",
|
||||
author=User(id=agent_id, username=agent_id),
|
||||
created_at=datetime.now(timezone.utc)
|
||||
))
|
||||
|
||||
def read_agent_messages(issue_id: str, msg_type: str = None):
|
||||
"""Read messages from other agents."""
|
||||
comments = backend.get_comments(issue_id)
|
||||
messages = []
|
||||
for comment in comments:
|
||||
if '```agent-message' in comment.body:
|
||||
try:
|
||||
json_str = comment.body.split('```agent-message\n')[1].split('\n```')[0]
|
||||
msg = json.loads(json_str)
|
||||
if msg_type is None or msg['type'] == msg_type:
|
||||
messages.append(msg)
|
||||
except:
|
||||
continue
|
||||
return messages
|
||||
```
|
||||
|
||||
## Configuration Check
|
||||
|
||||
Before using issue tracking, verify configuration:
|
||||
|
||||
```python
|
||||
def verify_issue_backend() -> bool:
|
||||
"""Verify issue backend is configured."""
|
||||
try:
|
||||
backend = GiteaBackend()
|
||||
backend.connect({
|
||||
'base_url': os.environ['GITEA_URL'],
|
||||
'token': os.environ['GITEA_API_TOKEN'],
|
||||
'owner': os.environ['GITEA_OWNER'],
|
||||
'repo': os.environ['GITEA_REPO']
|
||||
})
|
||||
return backend.test_connection()
|
||||
except Exception as e:
|
||||
print(f"Issue backend not configured: {e}")
|
||||
return False
|
||||
|
||||
# Use it
|
||||
if not verify_issue_backend():
|
||||
print("ERROR: Issue tracking not available. Check configuration.")
|
||||
sys.exit(1)
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
|
||||
```python
|
||||
from issue_tracker.backends.gitea.backend import GiteaAPIError
|
||||
|
||||
try:
|
||||
issue = backend.get_issue_by_number(42)
|
||||
except GiteaAPIError as e:
|
||||
if e.status_code == 404:
|
||||
print("Issue not found")
|
||||
elif e.status_code == 401:
|
||||
print("Authentication failed - check GITEA_API_TOKEN")
|
||||
elif e.status_code == 429:
|
||||
print("Rate limited - wait and retry")
|
||||
else:
|
||||
print(f"API error: {e}")
|
||||
```
|
||||
|
||||
## Performance Tips
|
||||
|
||||
1. **Use filters** instead of fetching all issues:
|
||||
```python
|
||||
# BAD: Get all, filter in Python
|
||||
all_issues = backend.list_issues()
|
||||
my_issues = [i for i in all_issues if i.assignees and i.assignees[0].username == 'me']
|
||||
|
||||
# GOOD: Filter at backend
|
||||
my_issues = backend.list_issues(IssueFilter(assignee='me'))
|
||||
```
|
||||
|
||||
2. **Use JSON output** for CLI parsing:
|
||||
```bash
|
||||
issue list --format=json | jq '.[] | select(.state == "open")'
|
||||
```
|
||||
|
||||
3. **Batch comments** instead of rapid-fire updates
|
||||
|
||||
4. **Check local cache** before querying (if available)
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### "Backend not configured"
|
||||
```bash
|
||||
# Check config
|
||||
issue backend list
|
||||
|
||||
# If empty, configure
|
||||
export GITEA_API_TOKEN="your-token"
|
||||
issue backend add myproject gitea
|
||||
issue backend set-default myproject
|
||||
```
|
||||
|
||||
### "Authentication failed"
|
||||
```bash
|
||||
# Verify token
|
||||
curl -H "Authorization: token $GITEA_API_TOKEN" $GITEA_URL/api/v1/user
|
||||
```
|
||||
|
||||
### "Issue not found"
|
||||
```python
|
||||
# Use get_issue_by_number, not get_issue
|
||||
issue = backend.get_issue_by_number(42) # Correct
|
||||
# issue = backend.get_issue("42") # Wrong - needs backend_id
|
||||
```
|
||||
|
||||
## Full Documentation
|
||||
|
||||
- **Integration Guide:** `AGENT_INTEGRATION.md` (comprehensive patterns and strategies)
|
||||
- **API Reference:** `CLAUDE.md` (for developers extending the capability)
|
||||
- **Examples:** `examples/agents/` (working agent implementations)
|
||||
- **Roadmap:** `ROADMAP.md` (upcoming features)
|
||||
|
||||
## Current Limitations (v1.0)
|
||||
|
||||
Be aware of these limitations:
|
||||
|
||||
1. **Manual Configuration:** Backend must be configured before use (auto-detect in v1.1)
|
||||
2. **User Context:** Uses hardcoded user for CLI operations (agent identity in v1.2)
|
||||
3. **No Built-in Locking:** Use assignee + comment workaround for claiming (native in v1.2)
|
||||
4. **Basic Conflicts:** Manual resolution required for complex sync conflicts (advanced in v2.0)
|
||||
|
||||
Workarounds are documented in `AGENT_INTEGRATION.md`.
|
||||
|
||||
## Questions?
|
||||
|
||||
If you're unsure whether to use this capability for something:
|
||||
|
||||
**ASK:** "Does this involve creating, reading, updating, or searching issues?"
|
||||
- **YES** → Use this capability
|
||||
- **NO** → You can use other methods
|
||||
|
||||
**Example:**
|
||||
- "Create an issue for the bug I found" → **Use issue-facade**
|
||||
- "Read the project README" → Don't need issue-facade
|
||||
- "Check if issue #42 exists" → **Use issue-facade**
|
||||
- "Clone the repository" → Don't need issue-facade
|
||||
6
.claude/commands/use-issues.md
Normal file
6
.claude/commands/use-issues.md
Normal file
@@ -0,0 +1,6 @@
|
||||
Use the issue-facade capability for all issue tracking operations.
|
||||
|
||||
**Quick reference:** See `.claude/capabilities/issue-facade.md`
|
||||
**Examples:** See `capabilities/issue-facade/examples/agents/`
|
||||
|
||||
**DO NOT use direct API calls or platform CLIs!**
|
||||
8
.claude/context/capabilities.md
Normal file
8
.claude/context/capabilities.md
Normal file
@@ -0,0 +1,8 @@
|
||||
# Available Capabilities
|
||||
|
||||
## Issue Tracking: issue-facade
|
||||
|
||||
**CRITICAL:** Always use this for issue operations. Never bypass with direct API calls.
|
||||
|
||||
**Docs:** `.claude/capabilities/issue-facade.md`
|
||||
**Usage:** `/use-issues`
|
||||
7
.gitmodules
vendored
7
.gitmodules
vendored
@@ -2,12 +2,13 @@
|
||||
path = wiki
|
||||
url = http://92.205.130.254:32166/coulomb/markitect_project.wiki.git
|
||||
branch = main
|
||||
[submodule "capabilities/issue-facade"]
|
||||
path = capabilities/issue-facade
|
||||
url = http://92.205.130.254:32166/coulomb/issue-facade.git
|
||||
[submodule "capabilities/kaizen-agentic"]
|
||||
path = capabilities/kaizen-agentic
|
||||
url = http://92.205.130.254:32166/coulomb/kaizen-agentic.git
|
||||
[submodule "capabilities/testdrive-jsui"]
|
||||
path = capabilities/testdrive-jsui
|
||||
url = http://92.205.130.254:32166/coulomb/testdrive-jsui.git
|
||||
[submodule "_issue-tracking/issue-facade"]
|
||||
path = _issue-tracking/issue-facade
|
||||
url = http://92.205.130.254:32166/coulomb/issue-facade.git
|
||||
branch = main
|
||||
|
||||
86
CHANGELOG.md
86
CHANGELOG.md
@@ -5,22 +5,106 @@ All notable changes to this project will be documented in this file.
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
See roadmap/YYMMDD-ROADMAPTOPIC/ directories for planning information like concepts, workplans, etc...
|
||||
See history/YYMMDD-ROADMAOTOPIC/ directories for planning information of closed topics
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
## [0.11.0] - 2026-01-06
|
||||
|
||||
### Added
|
||||
- Enhanced control panel UI with better resize handle positioning for improved user interaction
|
||||
- Release management optimizations: CHANGELOG validation, version-tag consistency checks
|
||||
- Automated tag pushing with --push/--no-push flag
|
||||
- Unpushed tags detection in release status
|
||||
|
||||
### Changed
|
||||
- Improved release validation workflow with CHANGELOG schema validation
|
||||
|
||||
|
||||
## [0.10.0] - 2026-01-06
|
||||
|
||||
### Added
|
||||
- **Schema Management System**: Comprehensive schema management infrastructure with naming conventions and versioning
|
||||
- Naming convention: `{domain}-schema-v{major}.{minor}.md` for all schemas
|
||||
- Markdown-first schema format with embedded JSON (documentation + schema in one file)
|
||||
- Schema catalog (`markitect/schemas/schema-catalog.yaml`) for metadata and discovery
|
||||
- Terminology validation example (`examples/terminology/`) demonstrating schema usage beyond manpages
|
||||
- Schema-of-schemas implementation archived in `history/2026-01-05-schema-of-schemas/`
|
||||
- **Enhanced schema-list Command**: Now displays numbered references in all output formats for easy selection
|
||||
- Simple format: `[1] schema-name.md` prefix for each schema
|
||||
- Table format: `#` column as first column
|
||||
- JSON/YAML: `number` field added to each schema
|
||||
- Default format shows timestamps inline: `schema-name.json (added: 2026-01-04T23:01:19)`
|
||||
- Table format includes Created/Updated columns
|
||||
- Cleaner timestamp formatting (removed microseconds)
|
||||
- **Multi-Schema Validation**: Enhanced schema-validate command with multiple selection methods
|
||||
- Number selection: `markitect schema-validate 1` validates schema #1
|
||||
- Range selection: `markitect schema-validate 1-3` validates schemas #1-3
|
||||
- List selection: `markitect schema-validate 1,3,5` validates schemas #1,3,5
|
||||
- Batch validation: `markitect schema-validate --all` validates all registered schemas
|
||||
- Filename selection: `markitect schema-validate schema.md` from registry
|
||||
- Filesystem path: `markitect schema-validate ./schema.md` from disk
|
||||
- Batch results displayed as clear summary table with validation status
|
||||
- Registry schemas take precedence over filesystem (with fallback)
|
||||
- Full backward compatibility with existing single-file validation
|
||||
- Enhanced control panel UI with better resize handle positioning for improved user interaction
|
||||
- **Semantic Document Validation**: Complete semantic validation system for markdown documents against x-markitect schema extensions
|
||||
- Section classification enforcement: required/recommended/optional/discouraged/improper sections validated
|
||||
- Content pattern validation: required_patterns, forbidden_patterns, discouraged_patterns with regex matching
|
||||
- Quality metrics checking: min_words, max_words, min_sentences validation with configurable thresholds
|
||||
- Link validation: Internal/external link checking with configurable policies
|
||||
- Internal links: Fragment anchors (#section) and file paths validated by default
|
||||
- External links: HTTP/HTTPS validation with --check-links flag (opt-in, may be slow)
|
||||
- Email validation: mailto: link format checking
|
||||
- Broken link detection with line numbers and detailed error messages
|
||||
- Modular validator architecture: SectionValidator, ContentValidator, LinkValidator with clean separation of concerns
|
||||
- CLI integration: `--semantic/--no-semantic`, `--strict`, `--check-links` flags for validate command
|
||||
- Comprehensive reporting: Detailed validation reports with errors/warnings, line numbers, matched text
|
||||
- Test coverage: 25 tests for semantic validators (16 section/content + 9 link), 100% passing
|
||||
- Full documentation: Semantic validation guide in SCHEMA_MANAGEMENT_GUIDE.md with examples
|
||||
- Complements existing structural AST validation for complete document compliance checking
|
||||
- **Changelog Schema**: Production schema for validating CHANGELOG.md files following Keep a Changelog format
|
||||
- Schema file: `changelog-schema-v1.0.md` validates version history structure and formatting
|
||||
- Enforces Unreleased section presence (required)
|
||||
- Validates version format: `[X.Y.Z] - YYYY-MM-DD` with semantic versioning
|
||||
- Validates change type subsections: Added, Changed, Deprecated, Removed, Fixed, Security
|
||||
- Content pattern validation for version sections, date formats (ISO 8601), and change types
|
||||
- Demonstrates real-world schema system usage: "The release that validates itself"
|
||||
- Successfully validates project CHANGELOG.md with all semantic checks passing
|
||||
|
||||
### Changed
|
||||
- **Directory Reorganization**:
|
||||
- Renamed `todo/` → `roadmap/` for better organization of planning documents
|
||||
- Completed schema-of-schemas implementation archived to `history/2026-01-05-schema-of-schemas/`
|
||||
- Moved completed planning artifacts to history for reference
|
||||
- Refactored contents control architecture to use base class pattern properly for better code organization
|
||||
- Updated all file references and paths to point to single source of truth in capabilities/testdrive-jsui/js/controls/ directory
|
||||
|
||||
### Fixed
|
||||
- **Version Detection Issue**: Fixed `markitect --version` returning "unknown" instead of actual version
|
||||
- Added `git_describe_command` to setuptools-scm configuration to filter version tags correctly
|
||||
- Configured git describe to use `--match 'v*'` pattern to ignore non-version tags
|
||||
- Version detection now works correctly with development versions (e.g., 0.9.1.dev76)
|
||||
- **Missing v0.9.0 Git Tag**: Retroactively created v0.9.0 annotated tag on commit b9c1b90 from 2025-11-14
|
||||
- Maintains version history integrity (CHANGELOG documented v0.9.0 but tag was missing)
|
||||
- Enables proper version progression to v0.10.0
|
||||
- Duplicate file structure issue by eliminating duplicate control files and consolidating to capabilities/ directory
|
||||
- Contents panel scrollbar behavior - moved overflow-y: auto to correct container level so scrollbar only spans content area when panel reaches max-height
|
||||
|
||||
### Removed
|
||||
- **BREAKING**: Legacy DocumentControls component from TestDrive JSUI plugin system - all control panel functionality now provided by enhanced control panels (ContentsControl, StatusControl, DebugControl, EditControl) with Reset All button functionality moved to EditControl for better maintainability and elimination of code duplication
|
||||
|
||||
### Completed Features
|
||||
- **Schema-of-Schemas Implementation** (All 6 Phases Complete ✅)
|
||||
- ✅ Phase 1: Filename validation for schema naming convention (`markitect/schema_naming.py`, 50 tests)
|
||||
- ✅ Phase 2: Markdown schema loader to parse `.md` schema files (`markitect/schema_loader.py`, 35 tests)
|
||||
- ✅ Phase 3: Schema-for-schemas metaschema for schema validation (`schema-schema-v1.0.md`, 12 tests)
|
||||
- ✅ Phase 4: Migration of 5 existing schemas to new format (migrated 2, deleted 3 duplicates)
|
||||
- ✅ Phase 5: CLI enhancements - numbered schema-list, multi-schema validation with selection methods
|
||||
- ✅ Phase 6: Integration testing and comprehensive documentation (SCHEMA_MANAGEMENT_GUIDE.md)
|
||||
- **Total Test Coverage**: 97 tests, 100% passing
|
||||
- **Complete Documentation**: Usage guide, naming spec, loader guide, metaschema reference
|
||||
|
||||
## [0.9.0] - 2025-11-14
|
||||
|
||||
### Added
|
||||
|
||||
149
TODO.html
149
TODO.html
@@ -1,149 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="generator" content="TestDrive JSUI Markitect 1.0.0">
|
||||
<title>TestDrive JSUI Document</title>
|
||||
|
||||
<style>
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Helvetica, Arial, sans-serif;
|
||||
max-width: 800px;
|
||||
margin: 0 auto;
|
||||
padding: 2rem;
|
||||
line-height: 1.6;
|
||||
color: #333333;
|
||||
background-color: #ffffff;
|
||||
}
|
||||
#markdown-content {
|
||||
min-height: 200px;
|
||||
}
|
||||
h1, h2, h3, h4, h5, h6 {
|
||||
color: #333333;
|
||||
}
|
||||
pre {
|
||||
background-color: #f6f8fa;
|
||||
color: #333333;
|
||||
padding: 1rem;
|
||||
border-radius: 6px;
|
||||
overflow-x: auto;
|
||||
border: 1px solid #d0d7de;
|
||||
}
|
||||
code {
|
||||
background-color: #f6f8fa;
|
||||
color: #333333;
|
||||
padding: 0.2em 0.4em;
|
||||
border-radius: 3px;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
pre code {
|
||||
background: none;
|
||||
padding: 0;
|
||||
}
|
||||
blockquote {
|
||||
border-left: 4px solid #dfe2e5;
|
||||
margin: 0;
|
||||
padding-left: 1rem;
|
||||
color: #6a737d;
|
||||
}
|
||||
table {
|
||||
font-size: 0.85em;
|
||||
border-collapse: collapse;
|
||||
margin: 1rem 0;
|
||||
width: 100%;
|
||||
border: 1px solid #d0d7de;
|
||||
}
|
||||
th, td {
|
||||
font-size: inherit;
|
||||
border: 1px solid #d0d7de;
|
||||
padding: 0.5rem;
|
||||
text-align: left;
|
||||
}
|
||||
th {
|
||||
background-color: #f6f8fa;
|
||||
font-weight: 600;
|
||||
}
|
||||
img {
|
||||
max-width: 12cm;
|
||||
max-height: 20cm;
|
||||
height: auto;
|
||||
display: block;
|
||||
margin: 1rem auto;
|
||||
}
|
||||
</style>
|
||||
|
||||
<!-- Plugin-specific CSS -->
|
||||
<link rel="stylesheet" href="_markitect/plugins/testdrive-jsui/static/css/editor.css">
|
||||
<link rel="stylesheet" href="_markitect/plugins/testdrive-jsui/static/css/controls.css">
|
||||
<link rel="stylesheet" href="_markitect/plugins/testdrive-jsui/static/css/themes/github.css">
|
||||
|
||||
<!-- External dependencies -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"
|
||||
onload="window.markitectMarkedLoaded = true"
|
||||
onerror="console.error('CDN library failed to load - network or firewall blocking marked.js'); window.markitectMarkedError = true;"></script>
|
||||
</head>
|
||||
<body class="markitect-edit-mode">
|
||||
|
||||
<!-- Content container with fallback content -->
|
||||
<div id="markdown-content">
|
||||
<h1>Todofile</h1></p><p>This is a "to do next" file, particularly useful to keep the human and a coding assistant in sync.</p><p>The format is based on [Keep a Todofile V0.0.1](https://coulomb.social/open/KeepaTodofile).</p><p>The structure organizes **future tasks** by their impact, just as a changelog organizes past changes by their impact.</p><p>***</p><p><h2>[Unreleased] - *Active Vibe-Coding State* 💡</h2></p><p>This section is for tasks currently being discussed with or worked on by the coding assistant. These are the ephemeral, flow-of-thought tasks.</p><p>*No active tasks at this time.*</p><p>***</p><p><h2>Completed Tasks</h2></p><p>*Recent completed tasks have been documented in CHANGELOG.md following Keep a Changelog format.*
|
||||
</div>
|
||||
|
||||
<!-- Configuration Data Interface - Clean JSON configuration -->
|
||||
<script id="markitect-config" type="application/json">{
|
||||
"markdownContent": "# Todofile\n\nThis is a \"to do next\" file, particularly useful to keep the human and a coding assistant in sync.\n\nThe format is based on [Keep a Todofile V0.0.1](https://coulomb.social/open/KeepaTodofile).\n\nThe structure organizes **future tasks** by their impact, just as a changelog organizes past changes by their impact.\n\n***\n\n## [Unreleased] - *Active Vibe-Coding State* \ud83d\udca1\n\nThis section is for tasks currently being discussed with or worked on by the coding assistant. These are the ephemeral, flow-of-thought tasks.\n\n*No active tasks at this time.*\n\n***\n\n## Completed Tasks\n\n*Recent completed tasks have been documented in CHANGELOG.md following Keep a Changelog format.*",
|
||||
"markdownContentWithDogtag": "# Todofile\n\nThis is a \"to do next\" file, particularly useful to keep the human and a coding assistant in sync.\n\nThe format is based on [Keep a Todofile V0.0.1](https://coulomb.social/open/KeepaTodofile).\n\nThe structure organizes **future tasks** by their impact, just as a changelog organizes past changes by their impact.\n\n***\n\n## [Unreleased] - *Active Vibe-Coding State* \ud83d\udca1\n\nThis section is for tasks currently being discussed with or worked on by the coding assistant. These are the ephemeral, flow-of-thought tasks.\n\n*No active tasks at this time.*\n\n***\n\n## Completed Tasks\n\n*Recent completed tasks have been documented in CHANGELOG.md following Keep a Changelog format.*",
|
||||
"dogtagContent": "",
|
||||
"mode": "edit",
|
||||
"theme": "github",
|
||||
"keyboardShortcuts": true,
|
||||
"autosave": false,
|
||||
"sections": true,
|
||||
"originalFilename": "document",
|
||||
"base64References": {},
|
||||
"version": "Markitect 1.0.0",
|
||||
"repoName": "Markitect"
|
||||
}</script>
|
||||
|
||||
<!-- Plugin JavaScript Assets -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
|
||||
<script src="_markitect/plugins/testdrive-jsui/static/js/core/debug-system.js"></script>
|
||||
<script src="_markitect/plugins/testdrive-jsui/static/js/core/section-manager.js"></script>
|
||||
<script src="_markitect/plugins/testdrive-jsui/static/js/components/debug-panel.js"></script>
|
||||
<script src="_markitect/plugins/testdrive-jsui/static/js/components/document-controls.js"></script>
|
||||
<script src="_markitect/plugins/testdrive-jsui/static/js/components/dom-renderer.js"></script>
|
||||
<script src="_markitect/plugins/testdrive-jsui/static/js/controls/control-base.js"></script>
|
||||
<script src="_markitect/plugins/testdrive-jsui/static/js/controls/contents-control.js"></script>
|
||||
<script src="_markitect/plugins/testdrive-jsui/static/js/controls/status-control.js"></script>
|
||||
<script src="_markitect/plugins/testdrive-jsui/static/js/controls/debug-control.js"></script>
|
||||
<script src="_markitect/plugins/testdrive-jsui/static/js/controls/edit-control.js"></script>
|
||||
<script src="_markitect/plugins/testdrive-jsui/static/js/config-loader.js"></script>
|
||||
<script src="_markitect/plugins/testdrive-jsui/static/js/main-updated.js"></script>
|
||||
|
||||
<!-- Initialization Script -->
|
||||
<script>
|
||||
window.addEventListener('load', function() {
|
||||
console.log('🎯 TestDrive JSUI loading complete, initializing...');
|
||||
|
||||
// Handle CDN loading errors
|
||||
if (window.markitectMarkedError) {
|
||||
console.error("CDN library failed to load - network or firewall blocking marked.js");
|
||||
}
|
||||
|
||||
// Initialize main application
|
||||
try {
|
||||
if (typeof MarkitectMain !== 'undefined') {
|
||||
console.log('🚀 Starting MarkitectMain initialization...');
|
||||
MarkitectMain.initialize();
|
||||
} else {
|
||||
console.warn('⚠️ MarkitectMain not available, edit functionality may be limited');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('❌ TestDrive JSUI initialization failed:', error);
|
||||
console.log('📄 Content should still be visible in fallback mode');
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
59
TODO.md
59
TODO.md
@@ -6,16 +6,67 @@ The format is based on [Keep a Todofile V0.0.1](https://coulomb.social/open/Keep
|
||||
|
||||
The structure organizes **future tasks** by their impact, just as a changelog organizes past changes by their impact.
|
||||
|
||||
See roadmap/YYMMDD-ROADMAPTOPIC/ directories for planning information like concepts, workplans, etc...
|
||||
|
||||
***
|
||||
|
||||
## [Unreleased] - *Active Vibe-Coding State* 💡
|
||||
|
||||
This section is for tasks currently being discussed with or worked on by the coding assistant. These are the ephemeral, flow-of-thought tasks.
|
||||
|
||||
*No active tasks at this time.*
|
||||
### Extract Capability-Capability from Issue-Facade (Paused)
|
||||
|
||||
***
|
||||
**Context:** Issue-facade currently provides two capabilities:
|
||||
1. **issue-tracking** (explicit in CAPABILITY-issue-tracking.yaml) - Issue management across platforms
|
||||
2. **capability-capability** (implicit) - Patterns and tools for creating/managing capabilities
|
||||
|
||||
## Completed Tasks
|
||||
The **capability-capability** includes:
|
||||
- Feedback pattern (feedback/ directory, .capability/feedback CLI tool, documentation)
|
||||
- Detachment facility (.capability/detach script for clean capability removal)
|
||||
- Integration pattern (.capability/integrate.sh for project integration)
|
||||
- CAPABILITY-*.yaml specification format
|
||||
- ReusableCapabilitiesArchitecture.md (complete specification)
|
||||
- Directory conventions (_family/implementation, visible/hidden patterns)
|
||||
|
||||
**Goal:** Extract capability-capability to separate `reusable-capability` repository so it can be used by any capability in the markitect ecosystem.
|
||||
|
||||
**Approach:** Step-by-step extraction, starting with specification.
|
||||
|
||||
#### Phase 1: Specification & Planning (Current)
|
||||
|
||||
- [ ] Create CAPABILITY-capability.yaml in issue-facade to explicitly declare the implicit capability
|
||||
- [ ] Define what belongs to capability-capability family vs issue-tracking family
|
||||
- [ ] Document the capability-capability API surface (what tools/patterns it provides)
|
||||
- [ ] Identify all files/directories to extract
|
||||
- [ ] Plan extraction strategy (copy vs move, how to maintain during transition)
|
||||
|
||||
#### Phase 2: Repository Creation
|
||||
|
||||
- [ ] Create reusable-capability repository structure
|
||||
- [ ] Extract ReusableCapabilitiesArchitecture.md to new repo
|
||||
- [ ] Extract feedback pattern (directory structure, CLI tool, README)
|
||||
- [ ] Extract detachment facility (.capability/detach)
|
||||
- [ ] Extract integration scripts (.capability/integrate.sh, integration-checklist.md)
|
||||
- [ ] Create CAPABILITY-capability.yaml in new repo (canonical version)
|
||||
- [ ] Add README.md for reusable-capability repo
|
||||
|
||||
#### Phase 3: Integration & Testing
|
||||
|
||||
- [ ] Update issue-facade to depend on reusable-capability (as integrated capability)
|
||||
- [ ] Integrate reusable-capability into issue-facade using _capability/reusable-capability pattern
|
||||
- [ ] Test that issue-facade still works with extracted capability
|
||||
- [ ] Update issue-facade documentation to reference both capabilities it provides/uses
|
||||
- [ ] Verify feedback system still works
|
||||
- [ ] Verify detachment still works
|
||||
|
||||
#### Phase 4: Dogfooding & Validation
|
||||
|
||||
- [ ] Choose another markitect capability for dogfooding
|
||||
- [ ] Integrate reusable-capability into that capability
|
||||
- [ ] Add feedback system to new capability
|
||||
- [ ] Add detachment facility to new capability
|
||||
- [ ] Document learnings and refine reusable-capability based on real-world usage
|
||||
- [ ] Update ReusableCapabilitiesArchitecture.md with insights
|
||||
|
||||
**Current Step:** Phase 1, Task 1 - Create CAPABILITY-capability.yaml
|
||||
|
||||
*Recent completed tasks have been documented in CHANGELOG.md following Keep a Changelog format.*
|
||||
1
_issue-tracking/issue-facade
Submodule
1
_issue-tracking/issue-facade
Submodule
Submodule _issue-tracking/issue-facade added at 70d7ec0cdc
@@ -15,19 +15,25 @@ You are the MarkiTect project assistant, specialized in providing project status
|
||||
|
||||
### Key Project Files & Their Purpose
|
||||
|
||||
- **ProjectStatusDigest.md**: The canonical source of truth for project architecture, features, and current state
|
||||
- **ProjectDiary.md**: Chronological record of major work packages, milestones, and development sessions
|
||||
- **TODO.md**: Task management and priorities following Keep a Todofile format for maintaining coding flow
|
||||
- **TODO.md**: Current state of implemenation based on the Keep-A-Todofile format for maintaining coding flow
|
||||
- **CHANGELOG.md**: History of releases based on the Keep-A-Changelog format for easy access to what happend before
|
||||
- **roadmap/**: Directory with current and close range roadmap-topic-directories for concepts, workplans, examples...
|
||||
- **history/**: Directory with closed roadmap-topic-directories including finishd TODO.md files as YYMMDD-DONE.md
|
||||
- **Makefile**: Provides helpers to use and improve the capabilities provided by the project
|
||||
**Gitea Issues**: Backlog of issues and backlog of tasks stored as issues in gitea
|
||||
**Gitea Issues**: Backlog of issues and backlog of tasks stored as issues in gitea before selection as roadmap topics
|
||||
|
||||
### Project Infrastructure Knowledge
|
||||
|
||||
**Repository Structure:**
|
||||
- Main project hosted on Gitea with issue tracking for use cases and tasks
|
||||
- Documentation maintained in `wiki/` submodule
|
||||
- Planning documentation goes to roadmap/ROADMAPTOPIC subdirectories
|
||||
- Closed roadmap-topic-directories git-mv to history/
|
||||
- Auto generated documentation maintained in docs/
|
||||
- Human generated documentation maintained in wiki/ submodule
|
||||
- Test-driven development workflow with comprehensive test coverage
|
||||
|
||||
Important: Respect the directory structure! If in doubt ask or use directories under tmp/ to keep the structure clean!
|
||||
|
||||
**Development Workflow:**
|
||||
- Issue-driven development using Gitea API integration
|
||||
- Issue management via universal issue-facade CLI that works with multiple backends
|
||||
@@ -56,17 +62,19 @@ You are the MarkiTect project assistant, specialized in providing project status
|
||||
|
||||
When asked about project status or next steps:
|
||||
|
||||
1. **Start with Current State**: Always check ProjectStatusDigest.md for the latest architecture and status
|
||||
2. **Review Recent Progress**: Check ProjectDiary.md for recent accomplishments and context
|
||||
3. **Check Planned Work**: Read Next.md for documented next steps and priorities
|
||||
4. **Consider Git Status**: Be aware of current working directory state and recent commits
|
||||
1. **Start with Current State**: Always check TODO.md for the latest activity
|
||||
2. **Review Recent Progress**: Check CHANGELOG.md for previous work and progress
|
||||
3. **Check Planned Work**: TODO.md documents next steps and priorities, if empty see topics in roadmap/
|
||||
4. **Project Scope and Goals**: Vision, Mission, Guidelines and Usecases live in wiki/ if available
|
||||
5. **Planning New Stuff**: Requirements (Epics and Stories) are gitea issues to be planned as roadmap topics
|
||||
6. **Consider Git Status**: Allways be aware of current working directory state and recent commits
|
||||
|
||||
### Issue Management Guidelines
|
||||
|
||||
**When to Create Gitea Issues:**
|
||||
- New feature requests or enhancement ideas emerge during development
|
||||
- Bugs or technical debt are discovered but not immediately fixable
|
||||
- Future improvements are identified but outside current session scope
|
||||
- Future improvements are identified but outside current session and topic scope
|
||||
- Architecture decisions require documentation and future review
|
||||
- Sidequests that we want to remember for later implementation
|
||||
|
||||
@@ -78,10 +86,12 @@ When asked about project status or next steps:
|
||||
- Do NOT implement immediately - issues are for tracking and planning
|
||||
|
||||
**Issue vs. Immediate Work:**
|
||||
- Current session planned work: implement directly (from Next.md)
|
||||
- Discovered improvements: create issue, continue with planned work
|
||||
- Current session planned work: document in TODO.md and roadmap/ROADMAPTOPIC
|
||||
- Discovered improvements: add to workplan in roadmap topic, continue with planned work
|
||||
- Critical bugs affecting current work: fix immediately, then create issue for root cause analysis
|
||||
- Future enhancements: always create issue first for proper planning
|
||||
- Future enhancements: note in roadmap-topic to create issues first for proper planning
|
||||
- If possible create issues interactively when closing a topic, they are for human oversight and longterm
|
||||
- Do not create issues for stuff that is detailed and can be adressed before closing the current topic
|
||||
|
||||
**Response Format:**
|
||||
- Provide a brief status summary (2-3 sentences)
|
||||
@@ -102,8 +112,6 @@ When asked about project status or next steps:
|
||||
1. [Action from Next.md or logical progression]
|
||||
2. [Secondary priority or alternative approach]
|
||||
3. [Maintenance or validation task if applicable]
|
||||
|
||||
Based on: ProjectStatusDigest.md:74-79, Next.md:7-13
|
||||
```
|
||||
|
||||
## Session Start-Up Protocol
|
||||
@@ -113,10 +121,10 @@ When asked what's up for a new coding session, follow this standardized routine:
|
||||
### Start-of-Session Checklist
|
||||
1. **Mission Status**: Provide reminder to project vision and how we are doing
|
||||
2. **Recently**: Provide reminder what we did last from the last entry to the diary
|
||||
3. **NEXT.txt**: Check if we provided guidance for what to do next at the end of the last coding session
|
||||
3. **TODO.md**: Check if we provided guidance for what to do next at the end of the last coding session
|
||||
4. **git status**: Check if git is clean or work has been left unfinished
|
||||
5. **Workspace clean**: Check if workspace is clean or we left of in the middle of a TDD cycle
|
||||
6. **Issue finished**: Check if we are currently working on a specific issue or need to select the next one
|
||||
6. **Topic or issue finished**: Check if we are currently working on a specific roadmap-topic or issue
|
||||
7. **Suggestion**: Provide a sensible suggestion of what to do next
|
||||
|
||||
## Session Wrap-Up Protocol
|
||||
@@ -124,11 +132,10 @@ When asked what's up for a new coding session, follow this standardized routine:
|
||||
When asked to help wrap up a development session, follow this standardized routine:
|
||||
|
||||
### End-of-Session Checklist:
|
||||
1. **Update ProjectDiary.md**: Add entry documenting progress, challenges, and achievements
|
||||
2. **Update TODO.md**: Set clear priorities and strategy for next session using todofile format
|
||||
3. **Update ProjectStatusDigest.md**: Refresh current status, metrics, and completed features
|
||||
3. **Update roadmap-topic directory information**: Refresh current status, metrics, and completed features
|
||||
4. **Issue Management**: Review and create any issues for sidequests and discoveries made during session
|
||||
5. **Anchor patterns**: Update this project-assistant definition with any new workflow patterns
|
||||
5. **Anchor patterns**: Add Update suggestions for this project-assistant definition with any new workflow patterns
|
||||
6. **Prepare for commit**: Ensure all documentation reflects current state
|
||||
|
||||
### Session Success Indicators:
|
||||
@@ -143,9 +150,9 @@ When asked to help wrap up a development session, follow this standardized routi
|
||||
[Brief overview of accomplishments and current state]
|
||||
|
||||
## Documentation Updates
|
||||
- ✅ ProjectDiary.md: [what was added]
|
||||
- ✅ Next.md: [priorities set]
|
||||
- ✅ ProjectStatusDigest.md: [status updated]
|
||||
- ✅ TODO.md: [priorities set]
|
||||
- ✅ roadmap/TOPIC files: [what was added or changed]
|
||||
- ✅ CHANGELOG.ms: [status updated especially on release]
|
||||
|
||||
## Issues Created/Updated
|
||||
- 🎯 Issue #X: [brief description] - [reason for creation]
|
||||
@@ -157,9 +164,19 @@ When asked to help wrap up a development session, follow this standardized routi
|
||||
Ready for commit: [list of files to commit]
|
||||
```
|
||||
|
||||
### Example Capture Small Off-Topic Improvements in roadmap/eat-the-frog:
|
||||
**Smell**: Different filename conventions od conflicting concepts, unclear guideance
|
||||
**Hunch**: Ideas to explore that need consideration if useful and in scope
|
||||
**Hickups**: Notes on inefficient or roundtripping implementation to analyse later
|
||||
|
||||
Collect these in the roadmap-topic-directory and move stuff to eat-the-frog on close if unfinished
|
||||
|
||||
### Example Issue Creation During Development:
|
||||
**Scenario**: While implementing CLI commands, discover that error messages could be improved
|
||||
**Action**: Create issue "Enhance CLI error messages with user-friendly formatting and suggestions"
|
||||
**Result**: Continue with current CLI implementation, address error enhancement in future session
|
||||
|
||||
Generate issues for relevantly expensive or risky stuff and in direct feedback with developers.
|
||||
Controled in-scope-work does not need the costly issue capture, refinement, selection roundtrip.
|
||||
|
||||
Remember: Your role is to help developers quickly understand "where we are" and "what should we do next" when picking up work on the MarkiTect project, and to ensure proper session wrap-up for continuity.
|
||||
51
capabilities/DETACHED-issue-facade.yaml
Normal file
51
capabilities/DETACHED-issue-facade.yaml
Normal file
@@ -0,0 +1,51 @@
|
||||
# Detachment Manifest
|
||||
# This file records the removal of the issue-facade capability
|
||||
# Use this information to re-integrate with updated architecture
|
||||
|
||||
detachment:
|
||||
timestamp: 2025-12-17T21:23:14Z
|
||||
capability_name: issue-facade
|
||||
capability_family: issue-tracking
|
||||
integration_pattern: capabilities-directory
|
||||
original_location: /home/worsch/markitect_project/capabilities/issue-facade
|
||||
|
||||
capability_metadata:
|
||||
spec_file: CAPABILITY-issue-tracking.yaml
|
||||
version: unknown
|
||||
implementation: unknown
|
||||
maturity: unknown
|
||||
|
||||
integration_details:
|
||||
parent_project: capabilities
|
||||
parent_path: /home/worsch/markitect_project/capabilities
|
||||
|
||||
re_integration_guide: |
|
||||
To re-integrate this capability using the new architecture:
|
||||
|
||||
# Option 1: Git submodule (recommended)
|
||||
cd /home/worsch/markitect_project/capabilities
|
||||
git submodule add <repo-url> _issue-facade
|
||||
pip install -e _issue-facade/
|
||||
|
||||
# Option 2: Clone directly
|
||||
cd /home/worsch/markitect_project/capabilities
|
||||
git clone <repo-url> _issue-facade
|
||||
pip install -e _issue-facade/
|
||||
|
||||
# Option 3: Copy into project
|
||||
cd /home/worsch/markitect_project/capabilities
|
||||
cp -r /path/to/issue-facade _issue-facade
|
||||
pip install -e _issue-facade/
|
||||
|
||||
Note: Use underscore prefix (_issue-facade) per ReusableCapabilitiesArchitecture
|
||||
|
||||
notes:
|
||||
- The original integration used pattern: capabilities-directory
|
||||
- New architecture recommends: underscore-prefix at repo root
|
||||
- See ReusableCapabilitiesArchitecture.md for details
|
||||
|
||||
repository_info:
|
||||
# Fill in if re-integrating from git
|
||||
git_url: "http://92.205.130.254:32166/coulomb/issue-facade.git" # e.g., https://github.com/markitect/issue-facade
|
||||
git_branch: "main" # e.g., main
|
||||
git_commit: "35daa514e59788250847cd706c43ea78f24c5c1d" # Optional: specific commit to use
|
||||
Submodule capabilities/issue-facade deleted from 34a8bc7d4c
Submodule capabilities/kaizen-agentic updated: 1e0ff82d74...afc038d98b
@@ -0,0 +1,10 @@
|
||||
"""
|
||||
CHANGELOG management tools.
|
||||
|
||||
This package provides tools for working with CHANGELOG.md files.
|
||||
"""
|
||||
|
||||
from .editor import ChangelogEditor
|
||||
from .parser import ChangelogParser
|
||||
|
||||
__all__ = ['ChangelogEditor', 'ChangelogParser']
|
||||
@@ -0,0 +1,207 @@
|
||||
"""
|
||||
CHANGELOG.md editor for programmatic updates.
|
||||
|
||||
This module provides tools for editing CHANGELOG.md files following
|
||||
the Keep a Changelog format.
|
||||
"""
|
||||
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
from typing import Optional, List
|
||||
|
||||
|
||||
class ChangelogEditor:
|
||||
"""Programmatic editor for CHANGELOG.md files."""
|
||||
|
||||
def __init__(self, changelog_path: Optional[Path] = None):
|
||||
"""Initialize changelog editor.
|
||||
|
||||
Args:
|
||||
changelog_path: Path to CHANGELOG.md file
|
||||
"""
|
||||
self.changelog_path = changelog_path or Path.cwd() / 'CHANGELOG.md'
|
||||
|
||||
def create_version_section(self, version: str, date: Optional[str] = None) -> bool:
|
||||
"""Create new version section and move Unreleased content.
|
||||
|
||||
Args:
|
||||
version: Version number (e.g., "0.11.0")
|
||||
date: Release date in YYYY-MM-DD format (defaults to today)
|
||||
|
||||
Returns:
|
||||
True if successful, False otherwise
|
||||
"""
|
||||
if date is None:
|
||||
date = datetime.now().strftime("%Y-%m-%d")
|
||||
|
||||
# Validate version format
|
||||
version_clean = version.lstrip('v')
|
||||
|
||||
if not self.changelog_path.exists():
|
||||
print(f"❌ CHANGELOG.md not found at {self.changelog_path}")
|
||||
return False
|
||||
|
||||
try:
|
||||
with open(self.changelog_path) as f:
|
||||
lines = f.readlines()
|
||||
|
||||
# Find Unreleased section
|
||||
unreleased_idx = None
|
||||
for i, line in enumerate(lines):
|
||||
if line.strip() == "## [Unreleased]":
|
||||
unreleased_idx = i
|
||||
break
|
||||
|
||||
if unreleased_idx is None:
|
||||
print("❌ No [Unreleased] section found in CHANGELOG.md")
|
||||
return False
|
||||
|
||||
# Find next version section or end of Unreleased content
|
||||
next_section_idx = None
|
||||
for i in range(unreleased_idx + 1, len(lines)):
|
||||
if lines[i].startswith("## [") and not lines[i].startswith("## [Unreleased]"):
|
||||
next_section_idx = i
|
||||
break
|
||||
|
||||
# Extract Unreleased content (skip the header line and first blank line)
|
||||
if next_section_idx:
|
||||
unreleased_content = lines[unreleased_idx + 1:next_section_idx]
|
||||
else:
|
||||
unreleased_content = lines[unreleased_idx + 1:]
|
||||
|
||||
# Check if there's actual content to move
|
||||
has_content = any(line.strip() and not line.strip().startswith('#')
|
||||
for line in unreleased_content)
|
||||
|
||||
if not has_content:
|
||||
print(f"⚠️ [Unreleased] section is empty. Add changes before creating release section.")
|
||||
print(f"💡 Tip: You can still create the section, but it will be empty.")
|
||||
|
||||
# Create new version section with moved content
|
||||
new_section_lines = [
|
||||
f"## [{version_clean}] - {date}\n",
|
||||
]
|
||||
|
||||
# Add the unreleased content (preserving structure)
|
||||
new_section_lines.extend(unreleased_content)
|
||||
|
||||
# Ensure proper spacing after new section
|
||||
if new_section_lines and not new_section_lines[-1].endswith('\n\n'):
|
||||
if not new_section_lines[-1].endswith('\n'):
|
||||
new_section_lines[-1] += '\n'
|
||||
new_section_lines.append('\n')
|
||||
|
||||
# Build new file content
|
||||
# Keep everything up to and including Unreleased header
|
||||
new_lines = lines[:unreleased_idx + 1]
|
||||
|
||||
# Add blank line after Unreleased header
|
||||
new_lines.append('\n')
|
||||
|
||||
# Add the new version section
|
||||
new_lines.extend(new_section_lines)
|
||||
|
||||
# Add remaining sections (if any)
|
||||
if next_section_idx:
|
||||
new_lines.extend(lines[next_section_idx:])
|
||||
|
||||
# Write back
|
||||
with open(self.changelog_path, 'w') as f:
|
||||
f.writelines(new_lines)
|
||||
|
||||
print(f"✅ Created section [{version_clean}] - {date} in CHANGELOG.md")
|
||||
if has_content:
|
||||
print(f"📝 Moved content from [Unreleased] to [{version_clean}]")
|
||||
print(f"💡 [Unreleased] section is now empty and ready for new changes")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"❌ Error editing CHANGELOG.md: {e}")
|
||||
return False
|
||||
|
||||
def get_version_content(self, version: str) -> Optional[List[str]]:
|
||||
"""Extract content for a specific version section.
|
||||
|
||||
Args:
|
||||
version: Version number to extract (e.g., "0.10.0")
|
||||
|
||||
Returns:
|
||||
List of lines in the version section, or None if not found
|
||||
"""
|
||||
version_clean = version.lstrip('v')
|
||||
|
||||
if not self.changelog_path.exists():
|
||||
return None
|
||||
|
||||
try:
|
||||
with open(self.changelog_path) as f:
|
||||
lines = f.readlines()
|
||||
|
||||
# Find the version section
|
||||
version_idx = None
|
||||
for i, line in enumerate(lines):
|
||||
if line.strip().startswith(f"## [{version_clean}]"):
|
||||
version_idx = i
|
||||
break
|
||||
|
||||
if version_idx is None:
|
||||
return None
|
||||
|
||||
# Find next section
|
||||
next_section_idx = None
|
||||
for i in range(version_idx + 1, len(lines)):
|
||||
if lines[i].startswith("## ["):
|
||||
next_section_idx = i
|
||||
break
|
||||
|
||||
# Extract content
|
||||
if next_section_idx:
|
||||
return lines[version_idx:next_section_idx]
|
||||
else:
|
||||
return lines[version_idx:]
|
||||
|
||||
except Exception:
|
||||
return None
|
||||
|
||||
def has_unreleased_content(self) -> bool:
|
||||
"""Check if Unreleased section has any content.
|
||||
|
||||
Returns:
|
||||
True if Unreleased section has content, False otherwise
|
||||
"""
|
||||
if not self.changelog_path.exists():
|
||||
return False
|
||||
|
||||
try:
|
||||
with open(self.changelog_path) as f:
|
||||
lines = f.readlines()
|
||||
|
||||
# Find Unreleased section
|
||||
unreleased_idx = None
|
||||
for i, line in enumerate(lines):
|
||||
if line.strip() == "## [Unreleased]":
|
||||
unreleased_idx = i
|
||||
break
|
||||
|
||||
if unreleased_idx is None:
|
||||
return False
|
||||
|
||||
# Find next section
|
||||
next_section_idx = None
|
||||
for i in range(unreleased_idx + 1, len(lines)):
|
||||
if lines[i].startswith("## ["):
|
||||
next_section_idx = i
|
||||
break
|
||||
|
||||
# Check content
|
||||
if next_section_idx:
|
||||
content = lines[unreleased_idx + 1:next_section_idx]
|
||||
else:
|
||||
content = lines[unreleased_idx + 1:]
|
||||
|
||||
# Check if there's actual content (not just whitespace or section headers)
|
||||
return any(line.strip() and not line.strip().startswith('#')
|
||||
for line in content)
|
||||
|
||||
except Exception:
|
||||
return False
|
||||
@@ -0,0 +1,179 @@
|
||||
"""
|
||||
CHANGELOG.md parser for extracting release notes.
|
||||
|
||||
This module provides tools for parsing CHANGELOG.md files and extracting
|
||||
version-specific content for release notes.
|
||||
"""
|
||||
|
||||
import re
|
||||
from pathlib import Path
|
||||
from typing import Optional
|
||||
|
||||
|
||||
class ChangelogParser:
|
||||
"""Parse CHANGELOG.md files and extract release information."""
|
||||
|
||||
def __init__(self, changelog_path: Optional[Path] = None):
|
||||
"""Initialize changelog parser.
|
||||
|
||||
Args:
|
||||
changelog_path: Path to CHANGELOG.md file
|
||||
"""
|
||||
self.changelog_path = changelog_path or Path.cwd() / 'CHANGELOG.md'
|
||||
|
||||
def extract_version_section(self, version: str, format: str = 'markdown') -> str:
|
||||
"""Extract CHANGELOG section for a specific version.
|
||||
|
||||
Args:
|
||||
version: Version to extract (e.g., "0.10.0")
|
||||
format: Output format ('markdown', 'plain', 'html')
|
||||
|
||||
Returns:
|
||||
Formatted content of the version section
|
||||
"""
|
||||
if not self.changelog_path.exists():
|
||||
return f"Error: CHANGELOG.md not found at {self.changelog_path}"
|
||||
|
||||
try:
|
||||
version_clean = version.lstrip('v')
|
||||
|
||||
with open(self.changelog_path) as f:
|
||||
content = f.read()
|
||||
|
||||
# Find the version section using regex
|
||||
# Match: ## [VERSION] - DATE followed by content until next ## [
|
||||
pattern = rf"## \[{re.escape(version_clean)}\].*?\n\n(.*?)(?=\n## \[|\Z)"
|
||||
match = re.search(pattern, content, re.DOTALL)
|
||||
|
||||
if not match:
|
||||
return f"Error: No section found for version {version_clean} in CHANGELOG.md"
|
||||
|
||||
section_content = match.group(1).strip()
|
||||
|
||||
if not section_content:
|
||||
return f"Warning: Section for version {version_clean} exists but is empty"
|
||||
|
||||
# Format based on requested format
|
||||
if format == 'plain':
|
||||
return self._to_plain(section_content)
|
||||
elif format == 'html':
|
||||
return self._to_html(section_content)
|
||||
else:
|
||||
return section_content # markdown (default)
|
||||
|
||||
except Exception as e:
|
||||
return f"Error reading CHANGELOG: {e}"
|
||||
|
||||
def get_latest_version(self) -> Optional[str]:
|
||||
"""Get the latest version number from CHANGELOG.
|
||||
|
||||
Returns:
|
||||
Latest version string or None if not found
|
||||
"""
|
||||
if not self.changelog_path.exists():
|
||||
return None
|
||||
|
||||
try:
|
||||
with open(self.changelog_path) as f:
|
||||
content = f.read()
|
||||
|
||||
# Find first version section (skip Unreleased)
|
||||
pattern = r"## \[(\d+\.\d+\.\d+[^\]]*)\]"
|
||||
match = re.search(pattern, content)
|
||||
|
||||
return match.group(1) if match else None
|
||||
|
||||
except Exception:
|
||||
return None
|
||||
|
||||
def list_versions(self) -> list:
|
||||
"""List all versions in CHANGELOG.
|
||||
|
||||
Returns:
|
||||
List of version strings
|
||||
"""
|
||||
if not self.changelog_path.exists():
|
||||
return []
|
||||
|
||||
try:
|
||||
with open(self.changelog_path) as f:
|
||||
content = f.read()
|
||||
|
||||
# Find all version sections (excluding Unreleased)
|
||||
pattern = r"## \[(\d+\.\d+\.\d+[^\]]*)\]"
|
||||
matches = re.findall(pattern, content)
|
||||
|
||||
return matches
|
||||
|
||||
except Exception:
|
||||
return []
|
||||
|
||||
def _to_plain(self, markdown_content: str) -> str:
|
||||
"""Convert markdown content to plain text.
|
||||
|
||||
Args:
|
||||
markdown_content: Markdown formatted content
|
||||
|
||||
Returns:
|
||||
Plain text content
|
||||
"""
|
||||
# Remove markdown formatting
|
||||
plain = markdown_content
|
||||
|
||||
# Remove bold/italic
|
||||
plain = re.sub(r'\*\*([^*]+)\*\*', r'\1', plain) # bold
|
||||
plain = re.sub(r'\*([^*]+)\*', r'\1', plain) # italic
|
||||
plain = re.sub(r'__([^_]+)__', r'\1', plain) # bold (underscores)
|
||||
plain = re.sub(r'_([^_]+)_', r'\1', plain) # italic (underscores)
|
||||
|
||||
# Remove links but keep text
|
||||
plain = re.sub(r'\[([^\]]+)\]\([^\)]+\)', r'\1', plain)
|
||||
|
||||
# Remove inline code backticks
|
||||
plain = re.sub(r'`([^`]+)`', r'\1', plain)
|
||||
|
||||
# Convert headers to plain text with spacing
|
||||
plain = re.sub(r'^### (.+)$', r'\n\1:', plain, flags=re.MULTILINE)
|
||||
plain = re.sub(r'^## (.+)$', r'\n\1\n' + '=' * 40, plain, flags=re.MULTILINE)
|
||||
|
||||
return plain.strip()
|
||||
|
||||
def _to_html(self, markdown_content: str) -> str:
|
||||
"""Convert markdown content to HTML.
|
||||
|
||||
Args:
|
||||
markdown_content: Markdown formatted content
|
||||
|
||||
Returns:
|
||||
HTML formatted content
|
||||
"""
|
||||
try:
|
||||
import markdown
|
||||
return markdown.markdown(markdown_content)
|
||||
except ImportError:
|
||||
# Fallback to basic HTML conversion if markdown package not available
|
||||
html = markdown_content
|
||||
|
||||
# Headers
|
||||
html = re.sub(r'^### (.+)$', r'<h3>\1</h3>', html, flags=re.MULTILINE)
|
||||
html = re.sub(r'^## (.+)$', r'<h2>\1</h2>', html, flags=re.MULTILINE)
|
||||
|
||||
# Bold/italic
|
||||
html = re.sub(r'\*\*([^*]+)\*\*', r'<strong>\1</strong>', html)
|
||||
html = re.sub(r'\*([^*]+)\*', r'<em>\1</em>', html)
|
||||
|
||||
# Links
|
||||
html = re.sub(r'\[([^\]]+)\]\(([^\)]+)\)', r'<a href="\2">\1</a>', html)
|
||||
|
||||
# Code
|
||||
html = re.sub(r'`([^`]+)`', r'<code>\1</code>', html)
|
||||
|
||||
# Lists
|
||||
html = re.sub(r'^- (.+)$', r'<li>\1</li>', html, flags=re.MULTILINE)
|
||||
html = re.sub(r'(<li>.*</li>)', r'<ul>\1</ul>', html, flags=re.DOTALL)
|
||||
|
||||
# Paragraphs
|
||||
html = re.sub(r'\n\n', '</p><p>', html)
|
||||
html = f'<p>{html}</p>'
|
||||
|
||||
return html
|
||||
@@ -11,6 +11,9 @@ from typing import Optional
|
||||
|
||||
from ..core.manager import ReleaseManager
|
||||
from ..utils.version import VersionManager
|
||||
from ..changelog.editor import ChangelogEditor
|
||||
from ..changelog.parser import ChangelogParser
|
||||
from ..summary.generator import SummaryGenerator
|
||||
|
||||
|
||||
@click.group(invoke_without_command=True)
|
||||
@@ -55,6 +58,15 @@ def status(ctx):
|
||||
print(f"Latest Commit: {status_info['latest_commit']}")
|
||||
print(f"Latest Tag: {status_info['latest_tag'] or 'None'}")
|
||||
print(f"Uncommitted Changes: {'Yes' if status_info['has_changes'] else 'No'}")
|
||||
|
||||
# Show unpushed tags
|
||||
unpushed_tags = status_info.get('unpushed_tags', [])
|
||||
if unpushed_tags:
|
||||
print(f"\n⚠️ Unpushed Tags: {len(unpushed_tags)} tag(s) not pushed to origin")
|
||||
for tag in unpushed_tags:
|
||||
print(f" - {tag}")
|
||||
print(f"\n💡 Push tags with: git push origin {' '.join(unpushed_tags)}")
|
||||
print(f" Or push all tags: git push --tags")
|
||||
else:
|
||||
print("Git Repository: Not available")
|
||||
|
||||
@@ -104,8 +116,10 @@ def validate(ctx):
|
||||
@main.command()
|
||||
@click.option('--version', required=True, help='Version to tag (e.g., 0.8.0)')
|
||||
@click.option('--message', help='Tag message')
|
||||
@click.option('--push/--no-push', default=True,
|
||||
help='Automatically push tag to origin (default: --push)')
|
||||
@click.pass_context
|
||||
def tag(ctx, version: str, message: Optional[str]):
|
||||
def tag(ctx, version: str, message: Optional[str], push: bool):
|
||||
"""Create git tag for version."""
|
||||
manager = ReleaseManager(
|
||||
project_root=ctx.obj['project_root'],
|
||||
@@ -113,8 +127,10 @@ def tag(ctx, version: str, message: Optional[str]):
|
||||
force=ctx.obj['force']
|
||||
)
|
||||
|
||||
if manager.create_tag(version, message):
|
||||
if manager.create_tag(version, message, push=push):
|
||||
print(f"✅ Successfully created tag for version {version}")
|
||||
if not push:
|
||||
print(f"💡 Push tag with: git push origin v{version}")
|
||||
else:
|
||||
print(f"❌ Failed to create tag for version {version}")
|
||||
sys.exit(1)
|
||||
@@ -248,5 +264,153 @@ def version_info(ctx, suggest: bool):
|
||||
print(f" {key.replace('_', ' ').title()}: {value}")
|
||||
|
||||
|
||||
@main.command('check-consistency')
|
||||
@click.option('--version', required=True, help='Version to check (e.g., 0.10.0)')
|
||||
@click.pass_context
|
||||
def check_consistency(ctx, version: str):
|
||||
"""Check consistency between CHANGELOG version and git tags."""
|
||||
manager = ReleaseManager(
|
||||
project_root=ctx.obj['project_root'],
|
||||
dry_run=ctx.obj['dry_run'],
|
||||
force=ctx.obj['force']
|
||||
)
|
||||
|
||||
is_consistent, issues = manager.check_version_consistency(version)
|
||||
|
||||
if is_consistent:
|
||||
print(f"✅ Version {version} is consistent:")
|
||||
print(f" - CHANGELOG has section for {version}")
|
||||
print(f" - Git tag v{version} exists")
|
||||
print(f" - [Unreleased] section present")
|
||||
else:
|
||||
print(f"❌ Version {version} has consistency issues:")
|
||||
for issue in issues:
|
||||
print(f" - {issue}")
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
@main.command('prepare')
|
||||
@click.argument('version')
|
||||
@click.option('--date', default=None, help='Release date (YYYY-MM-DD, defaults to today)')
|
||||
@click.pass_context
|
||||
def prepare(ctx, version: str, date: Optional[str]):
|
||||
"""Prepare CHANGELOG for new version release.
|
||||
|
||||
Creates a new version section in CHANGELOG.md and moves all content
|
||||
from the [Unreleased] section to the new version section.
|
||||
"""
|
||||
project_root = ctx.obj['project_root'] or Path.cwd()
|
||||
changelog_path = project_root / 'CHANGELOG.md'
|
||||
|
||||
editor = ChangelogEditor(changelog_path)
|
||||
|
||||
# Create version section
|
||||
if editor.create_version_section(version, date):
|
||||
# Validate result
|
||||
manager = ReleaseManager(
|
||||
project_root=ctx.obj['project_root'],
|
||||
dry_run=ctx.obj['dry_run'],
|
||||
force=ctx.obj['force']
|
||||
)
|
||||
|
||||
# Check if CHANGELOG is valid after edit
|
||||
is_valid, issues = manager.validate_release_state()
|
||||
|
||||
if is_valid:
|
||||
print("\n✅ CHANGELOG validation passed")
|
||||
else:
|
||||
print("\n⚠️ CHANGELOG validation issues after edit:")
|
||||
for issue in issues:
|
||||
if 'CHANGELOG' in issue:
|
||||
print(f" - {issue}")
|
||||
else:
|
||||
print(f"❌ Failed to prepare CHANGELOG for version {version}")
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
@main.command('summary')
|
||||
@click.argument('version')
|
||||
@click.option('--output', '-o', default=None, type=click.Path(path_type=Path),
|
||||
help='Output file path (defaults to RELEASE_SUMMARY_vX.Y.Z.md)')
|
||||
@click.pass_context
|
||||
def summary(ctx, version: str, output: Optional[Path]):
|
||||
"""Generate release summary document.
|
||||
|
||||
Extracts CHANGELOG content, git statistics, build artifacts, and
|
||||
validation results to create a comprehensive release summary.
|
||||
"""
|
||||
project_root = ctx.obj['project_root'] or Path.cwd()
|
||||
|
||||
# Default output path
|
||||
if output is None:
|
||||
version_clean = version.lstrip('v')
|
||||
output = project_root / f"RELEASE_SUMMARY_v{version_clean}.md"
|
||||
elif not output.is_absolute():
|
||||
output = project_root / output
|
||||
|
||||
generator = SummaryGenerator(project_root)
|
||||
|
||||
try:
|
||||
content = generator.generate(version, output_path=output)
|
||||
print(f"\n✅ Release summary generated successfully")
|
||||
print(f"📄 Summary saved to: {output}")
|
||||
except Exception as e:
|
||||
print(f"❌ Failed to generate release summary: {e}")
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
@main.command('notes')
|
||||
@click.argument('version', required=False)
|
||||
@click.option('--format', 'output_format', type=click.Choice(['markdown', 'plain', 'html']),
|
||||
default='markdown', help='Output format (default: markdown)')
|
||||
@click.option('--output', '-o', default=None, type=click.Path(path_type=Path),
|
||||
help='Save to file instead of stdout')
|
||||
@click.pass_context
|
||||
def notes(ctx, version: Optional[str], output_format: str, output: Optional[Path]):
|
||||
"""Extract release notes from CHANGELOG.md.
|
||||
|
||||
Extracts the CHANGELOG section for a specific version and outputs it
|
||||
in various formats. Useful for creating GitHub/Gitea release notes.
|
||||
|
||||
If no version is specified, uses the latest version from CHANGELOG.
|
||||
|
||||
Examples:
|
||||
release notes 0.10.0 # Extract v0.10.0 notes (markdown)
|
||||
release notes # Extract latest version notes
|
||||
release notes 0.10.0 --format plain # Plain text format
|
||||
release notes 0.10.0 -o notes.md # Save to file
|
||||
release notes 0.10.0 | gh release create v0.10.0 -F - # Pipe to gh
|
||||
"""
|
||||
project_root = ctx.obj['project_root'] or Path.cwd()
|
||||
changelog_path = project_root / 'CHANGELOG.md'
|
||||
|
||||
parser = ChangelogParser(changelog_path)
|
||||
|
||||
# Get version (use latest if not specified)
|
||||
if version is None:
|
||||
version = parser.get_latest_version()
|
||||
if version is None:
|
||||
print("❌ Could not determine version from CHANGELOG.md")
|
||||
sys.exit(1)
|
||||
print(f"Using latest version: {version}", file=sys.stderr)
|
||||
|
||||
# Extract content
|
||||
content = parser.extract_version_section(version, format=output_format)
|
||||
|
||||
# Check for errors
|
||||
if content.startswith("Error:") or content.startswith("Warning:"):
|
||||
print(content)
|
||||
sys.exit(1 if content.startswith("Error:") else 0)
|
||||
|
||||
# Output
|
||||
if output:
|
||||
if not output.is_absolute():
|
||||
output = project_root / output
|
||||
output.write_text(content)
|
||||
print(f"✅ Release notes written to {output}", file=sys.stderr)
|
||||
else:
|
||||
print(content)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -75,12 +75,13 @@ class ReleaseManager:
|
||||
"""
|
||||
return self.validator.validate_release_state(force=self.force)
|
||||
|
||||
def create_tag(self, version: str, message: Optional[str] = None) -> bool:
|
||||
def create_tag(self, version: str, message: Optional[str] = None, push: bool = True) -> bool:
|
||||
"""Create a git tag for the release.
|
||||
|
||||
Args:
|
||||
version: Version to tag (e.g., "1.0.0")
|
||||
message: Optional tag message
|
||||
push: Whether to push the tag to origin (default: True)
|
||||
|
||||
Returns:
|
||||
True if tag created successfully, False otherwise
|
||||
@@ -93,7 +94,16 @@ class ReleaseManager:
|
||||
print(f" - {issue}")
|
||||
return False
|
||||
|
||||
return self.git_manager.create_tag(version, message)
|
||||
# Check version-tag consistency (ensure CHANGELOG has version section)
|
||||
changelog_valid, changelog_issues = self.validator.validate_changelog_version(version)
|
||||
if not changelog_valid and not self.force:
|
||||
print(f"❌ Cannot create tag for version {version}:")
|
||||
for issue in changelog_issues:
|
||||
print(f" - {issue}")
|
||||
print("\n💡 Tip: Add a section for version {version} to CHANGELOG.md before tagging")
|
||||
return False
|
||||
|
||||
return self.git_manager.create_tag(version, message, push=push)
|
||||
|
||||
def build_packages(self) -> bool:
|
||||
"""Build release packages.
|
||||
@@ -212,4 +222,15 @@ class ReleaseManager:
|
||||
Returns:
|
||||
List of commit messages since last tag
|
||||
"""
|
||||
return self.git_manager.get_commits_since_tag()
|
||||
return self.git_manager.get_commits_since_tag()
|
||||
|
||||
def check_version_consistency(self, version: str) -> Tuple[bool, List[str]]:
|
||||
"""Check consistency between CHANGELOG version and git tags.
|
||||
|
||||
Args:
|
||||
version: Version to check (e.g., "0.10.0")
|
||||
|
||||
Returns:
|
||||
Tuple of (is_consistent, list_of_issues)
|
||||
"""
|
||||
return self.validator.check_version_tag_consistency(version)
|
||||
@@ -48,22 +48,27 @@ class GitManager:
|
||||
except subprocess.CalledProcessError:
|
||||
latest_tag = None
|
||||
|
||||
# Get unpushed tags
|
||||
unpushed_tags = self.get_unpushed_tags()
|
||||
|
||||
return {
|
||||
'is_repo': True,
|
||||
'branch': current_branch,
|
||||
'has_changes': has_changes,
|
||||
'latest_commit': latest_commit,
|
||||
'latest_tag': latest_tag
|
||||
'latest_tag': latest_tag,
|
||||
'unpushed_tags': unpushed_tags
|
||||
}
|
||||
except subprocess.CalledProcessError:
|
||||
return {'is_repo': False}
|
||||
|
||||
def create_tag(self, version: str, message: Optional[str] = None) -> bool:
|
||||
"""Create and push git tag.
|
||||
def create_tag(self, version: str, message: Optional[str] = None, push: bool = True) -> bool:
|
||||
"""Create and optionally push git tag.
|
||||
|
||||
Args:
|
||||
version: Version to tag (e.g., "1.0.0")
|
||||
message: Optional tag message
|
||||
push: Whether to push the tag to origin (default: True)
|
||||
|
||||
Returns:
|
||||
True if successful, False otherwise
|
||||
@@ -81,16 +86,19 @@ class GitManager:
|
||||
self._run_command(['git', 'tag', '-a', tag_name, '-m', tag_message])
|
||||
print(f"✅ Tag {tag_name} created")
|
||||
|
||||
# Push tag to origin
|
||||
try:
|
||||
print(f"📤 Pushing tag to origin...")
|
||||
self._run_command(['git', 'push', 'origin', tag_name])
|
||||
print(f"✅ Tag pushed to origin")
|
||||
return True
|
||||
except subprocess.CalledProcessError as e:
|
||||
print(f"⚠️ Could not push tag to origin: {e}")
|
||||
print(f"You can push it manually with: git push origin {tag_name}")
|
||||
return True # Tag created successfully, push can be done manually
|
||||
# Push tag to origin if requested
|
||||
if push:
|
||||
try:
|
||||
print(f"📤 Pushing tag to origin...")
|
||||
self._run_command(['git', 'push', 'origin', tag_name])
|
||||
print(f"✅ Tag pushed to origin")
|
||||
return True
|
||||
except subprocess.CalledProcessError as e:
|
||||
print(f"⚠️ Could not push tag to origin: {e}")
|
||||
print(f"You can push it manually with: git push origin {tag_name}")
|
||||
return True # Tag created successfully, push can be done manually
|
||||
else:
|
||||
return True # Tag created successfully, user chose not to push
|
||||
|
||||
except subprocess.CalledProcessError as e:
|
||||
print(f"❌ Failed to create tag: {e}")
|
||||
@@ -178,6 +186,47 @@ class GitManager:
|
||||
except subprocess.CalledProcessError:
|
||||
return None
|
||||
|
||||
def get_unpushed_tags(self, remote: str = 'origin') -> List[str]:
|
||||
"""Get list of tags that exist locally but not on remote.
|
||||
|
||||
Args:
|
||||
remote: Remote name to compare against (default: 'origin')
|
||||
|
||||
Returns:
|
||||
List of unpushed tag names
|
||||
"""
|
||||
try:
|
||||
# Get local tags
|
||||
local_result = self._run_command(['git', 'tag', '-l'])
|
||||
local_tags = set(tag.strip() for tag in local_result.stdout.strip().split('\n') if tag.strip())
|
||||
|
||||
# Get remote tags
|
||||
try:
|
||||
remote_result = self._run_command(['git', 'ls-remote', '--tags', remote])
|
||||
remote_lines = remote_result.stdout.strip().split('\n')
|
||||
|
||||
# Parse remote tags (format: "hash refs/tags/tagname")
|
||||
remote_tags = set()
|
||||
for line in remote_lines:
|
||||
if not line:
|
||||
continue
|
||||
parts = line.split('refs/tags/')
|
||||
if len(parts) > 1:
|
||||
# Remove ^{} suffix for annotated tags
|
||||
tag_name = parts[1].replace('^{}', '')
|
||||
remote_tags.add(tag_name)
|
||||
|
||||
# Find tags that are local but not remote
|
||||
unpushed = sorted(local_tags - remote_tags)
|
||||
return unpushed
|
||||
|
||||
except subprocess.CalledProcessError:
|
||||
# Remote not available, assume all tags are unpushed
|
||||
return sorted(local_tags)
|
||||
|
||||
except subprocess.CalledProcessError:
|
||||
return []
|
||||
|
||||
def _run_command(self, cmd: List[str]) -> subprocess.CompletedProcess:
|
||||
"""Run a git command.
|
||||
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
"""
|
||||
Release summary generation tools.
|
||||
|
||||
This package provides tools for generating release summary documents.
|
||||
"""
|
||||
|
||||
from .generator import SummaryGenerator
|
||||
|
||||
__all__ = ['SummaryGenerator']
|
||||
@@ -0,0 +1,305 @@
|
||||
"""
|
||||
Release summary generator.
|
||||
|
||||
This module generates comprehensive release summary documents from
|
||||
CHANGELOG content and git metadata.
|
||||
"""
|
||||
|
||||
import subprocess
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
from typing import Optional, Dict, Any, List
|
||||
import re
|
||||
|
||||
|
||||
class SummaryGenerator:
|
||||
"""Generate release summary documents."""
|
||||
|
||||
def __init__(self, project_root: Optional[Path] = None):
|
||||
"""Initialize summary generator.
|
||||
|
||||
Args:
|
||||
project_root: Root directory of the project
|
||||
"""
|
||||
self.project_root = project_root or Path.cwd()
|
||||
self.changelog_path = self.project_root / 'CHANGELOG.md'
|
||||
self.dist_dir = self.project_root / 'dist'
|
||||
|
||||
def generate(self, version: str, output_path: Optional[Path] = None) -> str:
|
||||
"""Generate release summary document.
|
||||
|
||||
Args:
|
||||
version: Version to generate summary for (e.g., "0.10.0")
|
||||
output_path: Optional path to write summary to
|
||||
|
||||
Returns:
|
||||
Generated summary content
|
||||
"""
|
||||
version_clean = version.lstrip('v')
|
||||
tag_name = f"v{version_clean}"
|
||||
|
||||
# Get components
|
||||
changelog_section = self.extract_changelog_section(version_clean)
|
||||
git_stats = self.get_git_statistics(tag_name)
|
||||
build_artifacts = self.list_build_artifacts()
|
||||
validation_results = self.get_validation_results()
|
||||
|
||||
# Determine project name
|
||||
project_name = self._get_project_name()
|
||||
|
||||
# Build summary
|
||||
summary = f"""# {project_name} {version_clean} Release Summary
|
||||
|
||||
**Release Date**: {git_stats.get('release_date', 'Unknown')}
|
||||
**Git Tag**: {tag_name}
|
||||
**Commit**: {git_stats.get('commit_hash', 'Unknown')}
|
||||
|
||||
---
|
||||
|
||||
## Changes
|
||||
|
||||
{changelog_section}
|
||||
|
||||
---
|
||||
|
||||
## Git Statistics
|
||||
|
||||
- **Commits**: {git_stats.get('commit_count', 0)} commit(s) since last release
|
||||
- **Files Changed**: {git_stats.get('files_changed', 0)} file(s)
|
||||
- **Insertions**: +{git_stats.get('insertions', 0)} lines
|
||||
- **Deletions**: -{git_stats.get('deletions', 0)} lines
|
||||
- **Contributors**: {git_stats.get('contributors', 'Unknown')}
|
||||
|
||||
---
|
||||
|
||||
## Build Artifacts
|
||||
|
||||
{build_artifacts}
|
||||
|
||||
---
|
||||
|
||||
## Validation
|
||||
|
||||
{validation_results}
|
||||
|
||||
---
|
||||
|
||||
**Generated**: {datetime.now().strftime("%Y-%m-%d %H:%M:%S")}
|
||||
"""
|
||||
|
||||
if output_path:
|
||||
output_path.write_text(summary)
|
||||
print(f"✅ Release summary written to {output_path}")
|
||||
|
||||
return summary
|
||||
|
||||
def extract_changelog_section(self, version: str) -> str:
|
||||
"""Extract CHANGELOG section for a specific version.
|
||||
|
||||
Args:
|
||||
version: Version to extract (e.g., "0.10.0")
|
||||
|
||||
Returns:
|
||||
Markdown content of the version section
|
||||
"""
|
||||
if not self.changelog_path.exists():
|
||||
return "⚠️ CHANGELOG.md not found"
|
||||
|
||||
try:
|
||||
with open(self.changelog_path) as f:
|
||||
content = f.read()
|
||||
|
||||
# Find the version section
|
||||
pattern = rf"## \[{re.escape(version)}\].*?\n\n(.*?)(?=\n## \[|\Z)"
|
||||
match = re.search(pattern, content, re.DOTALL)
|
||||
|
||||
if match:
|
||||
section_content = match.group(1).strip()
|
||||
return section_content if section_content else "No changes documented"
|
||||
else:
|
||||
return f"⚠️ No section found for version {version} in CHANGELOG.md"
|
||||
|
||||
except Exception as e:
|
||||
return f"❌ Error reading CHANGELOG: {e}"
|
||||
|
||||
def get_git_statistics(self, tag: str) -> Dict[str, Any]:
|
||||
"""Get git statistics for a release tag.
|
||||
|
||||
Args:
|
||||
tag: Git tag name (e.g., "v0.10.0")
|
||||
|
||||
Returns:
|
||||
Dictionary with git statistics
|
||||
"""
|
||||
stats = {}
|
||||
|
||||
try:
|
||||
# Get tag date
|
||||
try:
|
||||
result = subprocess.run(
|
||||
['git', 'log', '-1', '--format=%ci', tag],
|
||||
capture_output=True, text=True, check=True, cwd=self.project_root
|
||||
)
|
||||
date_str = result.stdout.strip()
|
||||
# Parse to get just the date
|
||||
stats['release_date'] = date_str.split()[0] if date_str else 'Unknown'
|
||||
except subprocess.CalledProcessError:
|
||||
stats['release_date'] = 'Unknown'
|
||||
|
||||
# Get commit hash
|
||||
try:
|
||||
result = subprocess.run(
|
||||
['git', 'rev-parse', tag],
|
||||
capture_output=True, text=True, check=True, cwd=self.project_root
|
||||
)
|
||||
stats['commit_hash'] = result.stdout.strip()[:8]
|
||||
except subprocess.CalledProcessError:
|
||||
stats['commit_hash'] = 'Unknown'
|
||||
|
||||
# Find previous tag
|
||||
try:
|
||||
result = subprocess.run(
|
||||
['git', 'describe', '--tags', '--abbrev=0', f'{tag}^'],
|
||||
capture_output=True, text=True, check=True, cwd=self.project_root
|
||||
)
|
||||
previous_tag = result.stdout.strip()
|
||||
except subprocess.CalledProcessError:
|
||||
# No previous tag, use initial commit
|
||||
previous_tag = None
|
||||
|
||||
# Get commit count
|
||||
if previous_tag:
|
||||
try:
|
||||
result = subprocess.run(
|
||||
['git', 'rev-list', '--count', f'{previous_tag}..{tag}'],
|
||||
capture_output=True, text=True, check=True, cwd=self.project_root
|
||||
)
|
||||
stats['commit_count'] = int(result.stdout.strip())
|
||||
except subprocess.CalledProcessError:
|
||||
stats['commit_count'] = 0
|
||||
else:
|
||||
try:
|
||||
result = subprocess.run(
|
||||
['git', 'rev-list', '--count', tag],
|
||||
capture_output=True, text=True, check=True, cwd=self.project_root
|
||||
)
|
||||
stats['commit_count'] = int(result.stdout.strip())
|
||||
except subprocess.CalledProcessError:
|
||||
stats['commit_count'] = 0
|
||||
|
||||
# Get file changes, insertions, deletions
|
||||
if previous_tag:
|
||||
diff_range = f'{previous_tag}..{tag}'
|
||||
else:
|
||||
diff_range = tag
|
||||
|
||||
try:
|
||||
result = subprocess.run(
|
||||
['git', 'diff', '--shortstat', diff_range],
|
||||
capture_output=True, text=True, check=True, cwd=self.project_root
|
||||
)
|
||||
shortstat = result.stdout.strip()
|
||||
|
||||
# Parse shortstat: "X files changed, Y insertions(+), Z deletions(-)"
|
||||
files_match = re.search(r'(\d+) files? changed', shortstat)
|
||||
insert_match = re.search(r'(\d+) insertions?', shortstat)
|
||||
delete_match = re.search(r'(\d+) deletions?', shortstat)
|
||||
|
||||
stats['files_changed'] = int(files_match.group(1)) if files_match else 0
|
||||
stats['insertions'] = int(insert_match.group(1)) if insert_match else 0
|
||||
stats['deletions'] = int(delete_match.group(1)) if delete_match else 0
|
||||
except subprocess.CalledProcessError:
|
||||
stats['files_changed'] = 0
|
||||
stats['insertions'] = 0
|
||||
stats['deletions'] = 0
|
||||
|
||||
# Get contributors
|
||||
try:
|
||||
result = subprocess.run(
|
||||
['git', 'log', '--format=%an', f'{previous_tag}..{tag}' if previous_tag else tag],
|
||||
capture_output=True, text=True, check=True, cwd=self.project_root
|
||||
)
|
||||
contributors = list(set(result.stdout.strip().split('\n')))
|
||||
stats['contributors'] = ', '.join(contributors) if contributors and contributors[0] else 'Unknown'
|
||||
except subprocess.CalledProcessError:
|
||||
stats['contributors'] = 'Unknown'
|
||||
|
||||
except Exception as e:
|
||||
print(f"⚠️ Error getting git statistics: {e}")
|
||||
|
||||
return stats
|
||||
|
||||
def list_build_artifacts(self) -> str:
|
||||
"""List build artifacts in dist/ directory.
|
||||
|
||||
Returns:
|
||||
Formatted markdown list of build artifacts
|
||||
"""
|
||||
if not self.dist_dir.exists():
|
||||
return "No build artifacts found (dist/ directory does not exist)"
|
||||
|
||||
artifacts = list(self.dist_dir.glob('*'))
|
||||
if not artifacts:
|
||||
return "No build artifacts found in dist/"
|
||||
|
||||
lines = []
|
||||
for artifact in sorted(artifacts):
|
||||
if artifact.is_file():
|
||||
size = artifact.stat().st_size
|
||||
size_kb = size / 1024
|
||||
size_mb = size / (1024 * 1024)
|
||||
|
||||
if size_mb >= 1:
|
||||
size_str = f"{size_mb:.2f} MB"
|
||||
else:
|
||||
size_str = f"{size_kb:.2f} KB"
|
||||
|
||||
lines.append(f"- **{artifact.name}** ({size_str})")
|
||||
|
||||
return '\n'.join(lines) if lines else "No build artifacts found"
|
||||
|
||||
def get_validation_results(self) -> str:
|
||||
"""Get validation results summary.
|
||||
|
||||
Returns:
|
||||
Formatted validation results
|
||||
"""
|
||||
# Import here to avoid circular dependency
|
||||
from ..utils.validation import ReleaseValidator
|
||||
|
||||
validator = ReleaseValidator(self.project_root)
|
||||
is_valid, issues = validator.validate_release_state(force=True) # Force to get all issues
|
||||
|
||||
if is_valid:
|
||||
return "✅ All validation checks passed"
|
||||
else:
|
||||
lines = ["Validation Issues:"]
|
||||
for issue in issues:
|
||||
lines.append(f"- {issue}")
|
||||
return '\n'.join(lines)
|
||||
|
||||
def _get_project_name(self) -> str:
|
||||
"""Get project name from pyproject.toml.
|
||||
|
||||
Returns:
|
||||
Project name or default
|
||||
"""
|
||||
pyproject_path = self.project_root / 'pyproject.toml'
|
||||
|
||||
if not pyproject_path.exists():
|
||||
return "Project"
|
||||
|
||||
try:
|
||||
import tomllib
|
||||
except ImportError:
|
||||
try:
|
||||
import tomli as tomllib
|
||||
except ImportError:
|
||||
return "Project"
|
||||
|
||||
try:
|
||||
with open(pyproject_path, 'rb') as f:
|
||||
config = tomllib.load(f)
|
||||
return config.get('project', {}).get('name', 'Project').title()
|
||||
except Exception:
|
||||
return "Project"
|
||||
@@ -4,6 +4,7 @@ Release validation utilities.
|
||||
This module provides validation functions for release readiness.
|
||||
"""
|
||||
|
||||
import subprocess
|
||||
from pathlib import Path
|
||||
from typing import List, Tuple, Optional
|
||||
|
||||
@@ -48,6 +49,10 @@ class ReleaseValidator:
|
||||
config_issues = self._validate_configuration()
|
||||
issues.extend(config_issues)
|
||||
|
||||
# CHANGELOG validation
|
||||
changelog_issues = self._validate_changelog()
|
||||
issues.extend(changelog_issues)
|
||||
|
||||
return len(issues) == 0, issues
|
||||
|
||||
def _validate_git_state(self) -> List[str]:
|
||||
@@ -186,6 +191,117 @@ class ReleaseValidator:
|
||||
|
||||
return len(issues) == 0, issues
|
||||
|
||||
def _validate_changelog(self) -> List[str]:
|
||||
"""Validate CHANGELOG.md using changelog schema.
|
||||
|
||||
Returns:
|
||||
List of CHANGELOG-related issues
|
||||
"""
|
||||
issues = []
|
||||
changelog_path = self.project_root / 'CHANGELOG.md'
|
||||
|
||||
# Check if CHANGELOG exists
|
||||
if not changelog_path.exists():
|
||||
issues.append("Missing CHANGELOG.md file")
|
||||
return issues
|
||||
|
||||
# Check if changelog schema exists
|
||||
schema_path = self.project_root / 'markitect' / 'schemas' / 'changelog-schema-v1.0.md'
|
||||
if not schema_path.exists():
|
||||
# Schema doesn't exist, skip validation
|
||||
return issues
|
||||
|
||||
# Validate CHANGELOG with schema using markitect validate command
|
||||
try:
|
||||
result = subprocess.run(
|
||||
[
|
||||
'markitect', 'validate', str(changelog_path),
|
||||
'--schema', str(schema_path),
|
||||
'--semantic'
|
||||
],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
cwd=self.project_root
|
||||
)
|
||||
|
||||
if result.returncode != 0:
|
||||
issues.append("CHANGELOG.md validation failed against schema")
|
||||
# Parse output for specific errors
|
||||
if 'Unreleased section' in result.stdout:
|
||||
issues.append(" - Missing [Unreleased] section in CHANGELOG")
|
||||
if 'version format' in result.stdout.lower():
|
||||
issues.append(" - Invalid version format in CHANGELOG")
|
||||
|
||||
except FileNotFoundError:
|
||||
# markitect command not available
|
||||
issues.append("Cannot validate CHANGELOG (markitect command not found)")
|
||||
except Exception as e:
|
||||
issues.append(f"Error validating CHANGELOG: {e}")
|
||||
|
||||
return issues
|
||||
|
||||
def validate_changelog_version(self, version: str) -> Tuple[bool, List[str]]:
|
||||
"""Validate that CHANGELOG has section for specified version.
|
||||
|
||||
Args:
|
||||
version: Version to check (e.g., "0.10.0")
|
||||
|
||||
Returns:
|
||||
Tuple of (is_valid, list_of_issues)
|
||||
"""
|
||||
issues = []
|
||||
changelog_path = self.project_root / 'CHANGELOG.md'
|
||||
|
||||
if not changelog_path.exists():
|
||||
issues.append("CHANGELOG.md not found")
|
||||
return False, issues
|
||||
|
||||
try:
|
||||
content = changelog_path.read_text()
|
||||
|
||||
# Check for version section
|
||||
version_header = f"## [{version}]"
|
||||
if version_header not in content:
|
||||
issues.append(f"CHANGELOG missing section for version {version}")
|
||||
|
||||
# Check for Unreleased section
|
||||
if "## [Unreleased]" not in content:
|
||||
issues.append("CHANGELOG missing [Unreleased] section")
|
||||
|
||||
# Check if version section has a date
|
||||
import re
|
||||
date_pattern = rf"## \[{re.escape(version)}\] - \d{{4}}-\d{{2}}-\d{{2}}"
|
||||
if not re.search(date_pattern, content):
|
||||
issues.append(f"Version {version} section missing date or has invalid date format")
|
||||
|
||||
except Exception as e:
|
||||
issues.append(f"Error reading CHANGELOG: {e}")
|
||||
|
||||
return len(issues) == 0, issues
|
||||
|
||||
def check_version_tag_consistency(self, version: str) -> Tuple[bool, List[str]]:
|
||||
"""Check consistency between CHANGELOG version and git tags.
|
||||
|
||||
Args:
|
||||
version: Version to check (e.g., "0.10.0")
|
||||
|
||||
Returns:
|
||||
Tuple of (is_consistent, list_of_issues)
|
||||
"""
|
||||
issues = []
|
||||
|
||||
# Check CHANGELOG has the version
|
||||
changelog_valid, changelog_issues = self.validate_changelog_version(version)
|
||||
if not changelog_valid:
|
||||
issues.extend(changelog_issues)
|
||||
|
||||
# Check git tag exists
|
||||
tag_name = version if version.startswith('v') else f'v{version}'
|
||||
if not self.git_manager.tag_exists(tag_name):
|
||||
issues.append(f"Git tag {tag_name} doesn't exist for version in CHANGELOG")
|
||||
|
||||
return len(issues) == 0, issues
|
||||
|
||||
def get_validation_summary(self) -> dict:
|
||||
"""Get a comprehensive validation summary.
|
||||
|
||||
@@ -224,6 +340,10 @@ class ReleaseValidator:
|
||||
if any('authentication' in issue.lower() for issue in issues):
|
||||
recommendations.append("Set up authentication tokens for package publishing")
|
||||
|
||||
if any('CHANGELOG' in issue for issue in issues):
|
||||
recommendations.append("Fix CHANGELOG.md format and ensure [Unreleased] section exists")
|
||||
recommendations.append("Validate with: markitect validate CHANGELOG.md --schema changelog-schema-v1.0.md --semantic")
|
||||
|
||||
if not issues:
|
||||
recommendations.append("Repository is ready for release!")
|
||||
|
||||
|
||||
Submodule capabilities/testdrive-jsui updated: 891d785533...b8f13b4ae5
548
docs/SCHEMA_MANAGEMENT_GUIDE.md
Normal file
548
docs/SCHEMA_MANAGEMENT_GUIDE.md
Normal file
@@ -0,0 +1,548 @@
|
||||
# Schema Management Guide
|
||||
|
||||
Complete guide to managing schemas in MarkiTect using the Schema-of-Schemas system.
|
||||
|
||||
## Overview
|
||||
|
||||
MarkiTect provides a comprehensive schema management system with:
|
||||
- Markdown-first schema format with embedded JSON
|
||||
- Strict naming conventions for consistency
|
||||
- Metaschema validation for all schemas
|
||||
- Multi-schema batch validation
|
||||
- Schema registry with version tracking
|
||||
|
||||
## Quick Start
|
||||
|
||||
### 1. Create a New Schema
|
||||
|
||||
Create a markdown file following the naming convention: `{domain}-schema-v{major}.{minor}.md`
|
||||
|
||||
```bash
|
||||
# Example: blog-post-schema-v1.0.md
|
||||
```
|
||||
|
||||
**Template:**
|
||||
|
||||
```markdown
|
||||
---
|
||||
schema-id: https://markitect.dev/schemas/blog-post/v1.0
|
||||
version: 1.0.0
|
||||
status: stable
|
||||
domain: blog-post
|
||||
description: Schema for blog post documents
|
||||
---
|
||||
|
||||
# Blog Post Schema v1.0.0
|
||||
|
||||
## Overview
|
||||
This schema validates blog post documents with frontmatter and content sections.
|
||||
|
||||
## Schema Definition
|
||||
|
||||
```json
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"$id": "https://markitect.dev/schemas/blog-post/v1.0",
|
||||
"title": "Blog Post Schema",
|
||||
"description": "Schema for blog post documents",
|
||||
"version": "1.0.0",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"title": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"author": {
|
||||
"type": "string"
|
||||
},
|
||||
"date": {
|
||||
"type": "string",
|
||||
"format": "date"
|
||||
}
|
||||
},
|
||||
"required": ["title", "author"]
|
||||
}
|
||||
```
|
||||
\`\`\`
|
||||
|
||||
### 2. Validate Your Schema
|
||||
|
||||
Validate against the metaschema to ensure it follows MarkiTect conventions:
|
||||
|
||||
```bash
|
||||
# Validate a single schema file
|
||||
markitect schema-validate ./blog-post-schema-v1.0.md
|
||||
|
||||
# See detailed errors
|
||||
markitect schema-validate ./blog-post-schema-v1.0.md --detailed-errors
|
||||
```
|
||||
|
||||
### 3. Ingest into Registry
|
||||
|
||||
Add your schema to the registry:
|
||||
|
||||
```bash
|
||||
markitect schema-ingest blog-post-schema-v1.0.md
|
||||
```
|
||||
|
||||
### 4. List Registered Schemas
|
||||
|
||||
View all schemas with numbered references:
|
||||
|
||||
```bash
|
||||
# Simple format (default)
|
||||
markitect schema-list
|
||||
|
||||
# Table format
|
||||
markitect schema-list --format table
|
||||
|
||||
# JSON format
|
||||
markitect schema-list --format json
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```
|
||||
Found 4 schema(s):
|
||||
|
||||
[1] 🔧 blog-post-schema-v1.0.md (added: 2026-01-05T10:30:00)
|
||||
[2] 🔧 schema-schema-v1.0.md (added: 2026-01-05T03:33:42)
|
||||
[3] 🔧 manpage-schema-v1.0.md (added: 2026-01-05T03:33:42)
|
||||
[4] 🔧 api-documentation-schema-v1.0.md (added: 2026-01-05T03:33:35)
|
||||
```
|
||||
|
||||
## Schema Validation
|
||||
|
||||
### Single Schema Validation
|
||||
|
||||
**By number:**
|
||||
```bash
|
||||
markitect schema-validate 1
|
||||
```
|
||||
|
||||
**By filename (from registry):**
|
||||
```bash
|
||||
markitect schema-validate blog-post-schema-v1.0.md
|
||||
```
|
||||
|
||||
**By filesystem path:**
|
||||
```bash
|
||||
markitect schema-validate ./my-schema.md
|
||||
```
|
||||
|
||||
### Batch Validation
|
||||
|
||||
**Validate a range:**
|
||||
```bash
|
||||
markitect schema-validate 1-3
|
||||
```
|
||||
|
||||
**Validate specific schemas:**
|
||||
```bash
|
||||
markitect schema-validate 1,3,5
|
||||
```
|
||||
|
||||
**Validate all schemas:**
|
||||
```bash
|
||||
markitect schema-validate --all
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```
|
||||
Validating 4 schema(s)...
|
||||
|
||||
Results:
|
||||
|
||||
# Schema Status Details
|
||||
--- -------------------------------- -------- ---------
|
||||
1 blog-post-schema-v1.0.md ✅ Valid v1.0.0
|
||||
2 schema-schema-v1.0.md ✅ Valid v1.0.0
|
||||
3 manpage-schema-v1.0.md ✅ Valid v1.0.0
|
||||
4 api-documentation-schema-v1.0.md ✅ Valid v1.0.0
|
||||
|
||||
Summary: 4 valid, 0 failed
|
||||
```
|
||||
|
||||
## Document Validation (Semantic)
|
||||
|
||||
### Validate Documents Against Schemas
|
||||
|
||||
Beyond validating schema structure, MarkiTect can validate actual markdown documents against schemas, checking both structural (AST) and semantic (x-markitect extensions) aspects.
|
||||
|
||||
**Validate a document:**
|
||||
|
||||
```bash
|
||||
# Full validation (structural + semantic)
|
||||
markitect validate my-document.md --schema manpage-schema-v1.0.md
|
||||
|
||||
# Only structural validation (classic mode)
|
||||
markitect validate my-document.md --schema schema.json --no-semantic
|
||||
|
||||
# With external link checking (may be slow)
|
||||
markitect validate my-document.md --schema manpage-schema-v1.0.md --check-links
|
||||
|
||||
# Strict mode (warnings become errors)
|
||||
markitect validate my-document.md --schema manpage-schema-v1.0.md --strict
|
||||
```
|
||||
|
||||
### What is Validated
|
||||
|
||||
**Structural Validation** (always enabled):
|
||||
- Document AST structure matches JSON Schema properties
|
||||
- Heading counts, paragraph counts, code block counts
|
||||
- Element types and nesting
|
||||
|
||||
**Semantic Validation** (enabled by default with --semantic):
|
||||
- **Section Classifications**: Checks that documents have required sections, don't have improper sections
|
||||
- REQUIRED sections must be present (ERROR if missing)
|
||||
- RECOMMENDED sections should be present (WARNING if missing)
|
||||
- IMPROPER sections must not be present (ERROR if found)
|
||||
- DISCOURAGED sections should not be present (WARNING if found)
|
||||
- OPTIONAL sections may or may not be present (no check)
|
||||
- **Content Patterns**: Validates content matches regex patterns
|
||||
- `required_patterns`: Content must match (ERROR if missing)
|
||||
- `forbidden_patterns`: Content must not match (ERROR if found)
|
||||
- `discouraged_patterns`: Content should not match (WARNING if found)
|
||||
- **Quality Metrics**: Checks word counts, sentence counts
|
||||
- `min_words`, `max_words`: Word count requirements (WARNING)
|
||||
- `min_sentences`: Minimum sentence count (WARNING)
|
||||
- **Link Validation**: Validates internal and external links (optional)
|
||||
- Internal links: Checked by default when semantic validation enabled
|
||||
- Fragment links (#section-name) verified to exist (ERROR if broken)
|
||||
- Relative file paths checked for existence (ERROR if broken)
|
||||
- External links: Opt-in with --check-links flag (may be slow)
|
||||
- HTTP/HTTPS URLs validated with HEAD requests (WARNING if broken)
|
||||
- Email validation: Validates mailto: link format (WARNING if invalid)
|
||||
- Fragment policy: Configurable allow/disallow fragment identifiers
|
||||
|
||||
### Validation Output
|
||||
|
||||
```
|
||||
Validation result: VALID
|
||||
File: my-command.1.md
|
||||
Schema: schema file: manpage-schema-v1.0.md
|
||||
✅ Document structure matches schema requirements
|
||||
|
||||
============================================================
|
||||
Semantic Validation Results:
|
||||
============================================================
|
||||
Section Validation:
|
||||
✅ SYNOPSIS - Present (required)
|
||||
✅ DESCRIPTION - Present (required)
|
||||
✅ EXAMPLES - Present (recommended)
|
||||
|
||||
Content Validation:
|
||||
✅ All content requirements met
|
||||
|
||||
Link Validation:
|
||||
✅ All 12 links valid
|
||||
|
||||
Summary:
|
||||
Sections checked: 3
|
||||
Sections found: 5
|
||||
Errors: 0
|
||||
Warnings: 0
|
||||
Status: PASSED ✅
|
||||
```
|
||||
|
||||
### Common Validation Scenarios
|
||||
|
||||
**Example 1: Missing Required Section**
|
||||
```bash
|
||||
$ markitect validate doc.md --schema manpage-schema-v1.0.md
|
||||
❌ Document validation failed
|
||||
|
||||
Section Validation:
|
||||
❌ SYNOPSIS - SYNOPSIS section is mandatory
|
||||
✅ DESCRIPTION - Present (required)
|
||||
|
||||
Errors: 1
|
||||
Status: FAILED ❌
|
||||
```
|
||||
|
||||
**Example 2: Forbidden Pattern Found**
|
||||
```bash
|
||||
$ markitect validate doc.md --schema manpage-schema-v1.0.md
|
||||
|
||||
Content Validation:
|
||||
❌ SYNOPSIS - Forbidden pattern found: 'TODO'
|
||||
|
||||
Errors: 1
|
||||
Status: FAILED ❌
|
||||
```
|
||||
|
||||
**Example 3: Content Too Short (Warning)**
|
||||
```bash
|
||||
$ markitect validate doc.md --schema manpage-schema-v1.0.md
|
||||
|
||||
Content Validation:
|
||||
⚠️ DESCRIPTION - Content too short (25 words, minimum 50)
|
||||
|
||||
Warnings: 1
|
||||
Status: PASSED ✅
|
||||
|
||||
# With --strict flag, this would fail:
|
||||
$ markitect validate doc.md --schema manpage-schema-v1.0.md --strict
|
||||
Status: FAILED ❌ (warnings treated as errors)
|
||||
```
|
||||
|
||||
**Example 4: Broken Internal Link**
|
||||
```bash
|
||||
$ markitect validate doc.md --schema manpage-schema-v1.0.md
|
||||
|
||||
Link Validation:
|
||||
❌ #nonexistent-section - Internal link target not found: #nonexistent-section
|
||||
|
||||
Errors: 1
|
||||
Status: FAILED ❌
|
||||
```
|
||||
|
||||
**Example 5: External Link Validation**
|
||||
```bash
|
||||
# Enable external link checking (may be slow)
|
||||
$ markitect validate doc.md --schema manpage-schema-v1.0.md --check-links
|
||||
|
||||
Link Validation:
|
||||
✅ http://example.com - Valid
|
||||
⚠️ http://broken-link.invalid - External link unreachable: Name or service not known
|
||||
|
||||
Warnings: 1
|
||||
Status: PASSED ✅
|
||||
```
|
||||
|
||||
## Schema Naming Conventions
|
||||
|
||||
All schema filenames must follow this pattern:
|
||||
|
||||
```
|
||||
{domain}-schema-v{major}.{minor}.md
|
||||
```
|
||||
|
||||
### Rules
|
||||
|
||||
- **Domain**: Lowercase letters, numbers, and hyphens only
|
||||
- **Version**: Major.minor format (e.g., `v1.0`, `v2.3`)
|
||||
- **Extension**: Must be `.md`
|
||||
- **No spaces**: Use hyphens for separation
|
||||
|
||||
### Valid Examples
|
||||
|
||||
- `blog-post-schema-v1.0.md`
|
||||
- `api-documentation-schema-v2.1.md`
|
||||
- `user-profile-schema-v1.0.md`
|
||||
|
||||
### Invalid Examples
|
||||
|
||||
- `BlogPost-schema-v1.0.md` (uppercase)
|
||||
- `blog_post-schema-v1.0.md` (underscore)
|
||||
- `blog-post-v1.0.md` (missing "schema")
|
||||
- `blog-post-schema-v1.md` (missing minor version)
|
||||
|
||||
## Required Schema Fields
|
||||
|
||||
All schemas must include these fields:
|
||||
|
||||
### Frontmatter (YAML)
|
||||
```yaml
|
||||
---
|
||||
schema-id: https://markitect.dev/schemas/{domain}/v{major}.{minor}
|
||||
version: {major}.{minor}.{patch}
|
||||
status: draft|stable|deprecated
|
||||
domain: {domain}
|
||||
description: Brief description
|
||||
---
|
||||
```
|
||||
|
||||
### JSON Schema
|
||||
```json
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"$id": "https://markitect.dev/schemas/{domain}/v{major}.{minor}",
|
||||
"title": "Schema Title",
|
||||
"description": "Schema description",
|
||||
"version": "{major}.{minor}.{patch}"
|
||||
}
|
||||
```
|
||||
|
||||
## Common Workflows
|
||||
|
||||
### Revalidate All Schemas After Metaschema Changes
|
||||
|
||||
When you update the metaschema, revalidate all registered schemas:
|
||||
|
||||
```bash
|
||||
markitect schema-validate --all
|
||||
```
|
||||
|
||||
### Check Schema Rigidity
|
||||
|
||||
Analyze a schema for overly rigid constraints:
|
||||
|
||||
```bash
|
||||
markitect schema-analyze my-schema.md
|
||||
```
|
||||
|
||||
### Refine a Rigid Schema
|
||||
|
||||
Automatically loosen overly specific constraints:
|
||||
|
||||
```bash
|
||||
# Dry run (preview changes)
|
||||
markitect schema-refine my-schema.md --dry-run
|
||||
|
||||
# Apply changes
|
||||
markitect schema-refine my-schema.md
|
||||
|
||||
# Interactive mode
|
||||
markitect schema-refine my-schema.md --interactive
|
||||
```
|
||||
|
||||
### Get Schema Details
|
||||
|
||||
View schema metadata:
|
||||
|
||||
```bash
|
||||
markitect schema-get blog-post-schema-v1.0.md
|
||||
```
|
||||
|
||||
### Delete a Schema
|
||||
|
||||
Remove a schema from the registry:
|
||||
|
||||
```bash
|
||||
markitect schema-delete blog-post-schema-v1.0.md --confirm
|
||||
```
|
||||
|
||||
## Resolution Precedence
|
||||
|
||||
When validating schemas, MarkiTect uses this resolution order:
|
||||
|
||||
1. **Registry (by filename)**: Exact match in the database
|
||||
2. **Filesystem (fallback)**: If not found in registry or looks like a path
|
||||
|
||||
### Examples
|
||||
|
||||
```bash
|
||||
# Looks up in registry first
|
||||
markitect schema-validate blog-post-schema-v1.0.md
|
||||
|
||||
# Forces filesystem lookup (contains /)
|
||||
markitect schema-validate ./blog-post-schema-v1.0.md
|
||||
|
||||
# Also forces filesystem
|
||||
markitect schema-validate ../schemas/blog-post-schema-v1.0.md
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
### Schema Development
|
||||
|
||||
1. **Start with a template**: Use an existing schema as a starting point
|
||||
2. **Validate early**: Validate against the metaschema before ingesting
|
||||
3. **Use semantic versioning**: Major.minor.patch for all versions
|
||||
4. **Document thoroughly**: Include overview, usage, and examples
|
||||
5. **Test with real documents**: Validate actual documents against your schema
|
||||
|
||||
### Version Management
|
||||
|
||||
- **Increment major version**: Breaking changes to schema structure
|
||||
- **Increment minor version**: Backward-compatible additions
|
||||
- **Increment patch version**: Bug fixes and clarifications
|
||||
|
||||
### Schema Organization
|
||||
|
||||
```
|
||||
markitect/schemas/
|
||||
├── schema-schema-v1.0.md # Metaschema
|
||||
├── manpage-schema-v1.0.md # Man page documents
|
||||
├── api-documentation-schema-v1.0.md
|
||||
├── terminology-schema-v1.0.md
|
||||
└── blog-post-schema-v1.0.md # Your schemas
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Schema Not Found
|
||||
|
||||
```
|
||||
❌ Schema 'my-schema.md' not found in registry or filesystem
|
||||
```
|
||||
|
||||
**Solution:** Use `markitect schema-list` to see available schemas, or provide a path: `./my-schema.md`
|
||||
|
||||
### Validation Fails
|
||||
|
||||
```
|
||||
❌ Schema validation failed: my-schema.md
|
||||
Found 2 validation error(s):
|
||||
```
|
||||
|
||||
**Solution:** Check error messages and compare with metaschema requirements. Use `--detailed-errors` for more context.
|
||||
|
||||
### Invalid Selector
|
||||
|
||||
```
|
||||
❌ Invalid selector: Range 1-10 is out of bounds. Valid range: 1-4
|
||||
```
|
||||
|
||||
**Solution:** Use `markitect schema-list` to see valid numbers, or check your range syntax.
|
||||
|
||||
## Advanced Usage
|
||||
|
||||
### Scripting with Schema Commands
|
||||
|
||||
Validate schemas in CI/CD:
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
# Validate all schemas and exit with error if any fail
|
||||
if ! markitect schema-validate --all; then
|
||||
echo "Schema validation failed!"
|
||||
exit 1
|
||||
fi
|
||||
echo "All schemas valid"
|
||||
```
|
||||
|
||||
### Batch Operations
|
||||
|
||||
```bash
|
||||
# Validate recently added schemas
|
||||
markitect schema-validate 1-3
|
||||
|
||||
# Validate specific critical schemas
|
||||
markitect schema-validate 1,5,8
|
||||
|
||||
# Check just the metaschema
|
||||
markitect schema-validate 2
|
||||
```
|
||||
|
||||
## Schema Extensions
|
||||
|
||||
MarkiTect supports custom extensions in schemas:
|
||||
|
||||
- `x-markitect-sections`: Section classification (required, recommended, optional, discouraged, improper)
|
||||
- `x-markitect-content-control`: Content validation rules and patterns
|
||||
- `x-markitect-metadata`: Additional metadata for MarkiTect processing
|
||||
|
||||
See existing schemas for examples of these extensions.
|
||||
|
||||
## Future Enhancements
|
||||
|
||||
Planned features:
|
||||
- Wildcard/globbing support: `markitect schema-validate */manpage*`
|
||||
- Schema diff tool: Compare schema versions
|
||||
- Schema migration assistant: Help upgrade documents to new schema versions
|
||||
|
||||
## Related Documentation
|
||||
|
||||
- [Schema Naming Specification](../history/260105-schema-of-schemas/SCHEMA_NAMING_SPEC.md)
|
||||
- [Schema Loader Guide](../history/260105-schema-of-schemas/SCHEMA_LOADER_GUIDE.md)
|
||||
- [Metaschema Reference](../markitect/schemas/schema-schema-v1.0.md)
|
||||
- [Implementation Workplan](../history/260105-schema-of-schemas/WORKPLAN.md) (archived)
|
||||
|
||||
## Support
|
||||
|
||||
For issues or questions:
|
||||
- Check existing schemas as examples
|
||||
- Review metaschema validation errors carefully
|
||||
- Use `--detailed-errors` for more context
|
||||
- Consult the metaschema for requirements
|
||||
662
docs/specifications/schema-extensions-spec.md
Normal file
662
docs/specifications/schema-extensions-spec.md
Normal file
@@ -0,0 +1,662 @@
|
||||
# MarkiTect Schema Extensions Specification v1.0
|
||||
|
||||
## Status: Draft - Phase 1 Implementation
|
||||
|
||||
## Overview
|
||||
|
||||
This specification defines MarkiTect-specific extensions to JSON Schema (draft-07) for markdown document validation with content control, section classification, and flexible structural constraints.
|
||||
|
||||
## Design Principles
|
||||
|
||||
1. **Backward Compatibility**: Existing schemas without extensions continue to work
|
||||
2. **Namespace Isolation**: All extensions prefixed with `x-markitect-`
|
||||
3. **Progressive Enhancement**: Extensions add capabilities without breaking standard JSON Schema
|
||||
4. **Clear Semantics**: Each extension has well-defined validation behavior
|
||||
5. **Metaschema Validation**: All extensions validated by MarkiTect metaschema
|
||||
|
||||
---
|
||||
|
||||
## Extension: `x-markitect-sections`
|
||||
|
||||
### Purpose
|
||||
|
||||
Define document sections with classification levels (required, recommended, optional, discouraged, improper) and content control specifications.
|
||||
|
||||
### Schema Location
|
||||
|
||||
Applied at the **root level** of the schema or within **properties** that represent document sections.
|
||||
|
||||
### Format
|
||||
|
||||
```json
|
||||
{
|
||||
"x-markitect-sections": {
|
||||
"SECTION_NAME": {
|
||||
"classification": "required|recommended|optional|discouraged|improper",
|
||||
"heading_level": 1|2|3|4|5|6,
|
||||
"position": "after_title|before_section_name|after_section_name|anywhere",
|
||||
"content_instruction": "string",
|
||||
"min_paragraphs": integer,
|
||||
"max_paragraphs": integer,
|
||||
"min_code_blocks": integer,
|
||||
"max_code_blocks": integer,
|
||||
"min_lists": integer,
|
||||
"max_lists": integer,
|
||||
"warning_if_missing": "string",
|
||||
"error_message": "string",
|
||||
"alternatives": ["SECTION_NAME_1", "SECTION_NAME_2"]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Property Definitions
|
||||
|
||||
#### `classification` (required)
|
||||
|
||||
Classification level determining validation behavior:
|
||||
|
||||
- **`required`**: Section MUST be present. Validation fails if missing.
|
||||
- **`recommended`**: Section SHOULD be present. Warning if missing, but validation succeeds.
|
||||
- **`optional`**: Section MAY be present. No validation impact either way.
|
||||
- **`discouraged`**: Section SHOULD NOT be present. Warning if present, but validation succeeds.
|
||||
- **`improper`**: Section MUST NOT be present. Validation fails if present.
|
||||
|
||||
**Type**: String enum
|
||||
**Required**: Yes
|
||||
**Values**: `["required", "recommended", "optional", "discouraged", "improper"]`
|
||||
|
||||
#### `heading_level` (optional)
|
||||
|
||||
The heading level (H1-H6) for this section.
|
||||
|
||||
**Type**: Integer
|
||||
**Range**: 1-6
|
||||
**Default**: 2 (for standard sections)
|
||||
|
||||
#### `position` (optional)
|
||||
|
||||
Where this section should appear relative to other sections.
|
||||
|
||||
**Type**: String enum
|
||||
**Values**:
|
||||
- `"after_title"` - Immediately after document title (H1)
|
||||
- `"before_section_name"` - Before another named section
|
||||
- `"after_section_name"` - After another named section
|
||||
- `"anywhere"` - No position constraint (default)
|
||||
|
||||
**Default**: `"anywhere"`
|
||||
|
||||
#### `content_instruction` (optional)
|
||||
|
||||
Human-readable instruction describing what content belongs in this section.
|
||||
|
||||
**Type**: String
|
||||
**Usage**: Displayed in validation warnings, generated templates, and documentation
|
||||
|
||||
**Example**:
|
||||
```json
|
||||
"content_instruction": "Brief command syntax showing all options and arguments"
|
||||
```
|
||||
|
||||
#### Content Constraints (optional)
|
||||
|
||||
Minimum and maximum counts for content elements within the section:
|
||||
|
||||
- **`min_paragraphs`**: Minimum paragraph count (integer ≥ 0)
|
||||
- **`max_paragraphs`**: Maximum paragraph count (integer ≥ min_paragraphs)
|
||||
- **`min_code_blocks`**: Minimum code block count (integer ≥ 0)
|
||||
- **`max_code_blocks`**: Maximum code block count (integer ≥ min_code_blocks)
|
||||
- **`min_lists`**: Minimum list count (integer ≥ 0)
|
||||
- **`max_lists`**: Maximum list count (integer ≥ max_lists)
|
||||
|
||||
**Type**: Integer
|
||||
**Default**: No constraint if omitted
|
||||
|
||||
#### `warning_if_missing` (optional)
|
||||
|
||||
Custom warning message when a recommended section is missing.
|
||||
|
||||
**Type**: String
|
||||
**Applies to**: `classification: "recommended"` only
|
||||
|
||||
**Example**:
|
||||
```json
|
||||
"warning_if_missing": "Examples greatly improve documentation usability"
|
||||
```
|
||||
|
||||
#### `error_message` (optional)
|
||||
|
||||
Custom error message when validation fails.
|
||||
|
||||
**Type**: String
|
||||
**Applies to**: `classification: "required"` or `"improper"`
|
||||
|
||||
**Example**:
|
||||
```json
|
||||
"error_message": "Internal notes must not appear in published documentation"
|
||||
```
|
||||
|
||||
#### `alternatives` (optional)
|
||||
|
||||
Array of alternative section names that satisfy the requirement.
|
||||
|
||||
**Type**: Array of strings
|
||||
**Usage**: If any alternative is present, requirement is satisfied
|
||||
|
||||
**Example**:
|
||||
```json
|
||||
{
|
||||
"classification": "required",
|
||||
"alternatives": ["EXAMPLES", "USAGE", "TUTORIAL"]
|
||||
}
|
||||
```
|
||||
|
||||
### Example: Manpage Schema with Sections
|
||||
|
||||
```json
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"title": "Unix Manpage Schema",
|
||||
"x-markitect-sections": {
|
||||
"SYNOPSIS": {
|
||||
"classification": "required",
|
||||
"heading_level": 2,
|
||||
"position": "after_title",
|
||||
"content_instruction": "Brief command syntax with options and arguments",
|
||||
"min_paragraphs": 1,
|
||||
"max_paragraphs": 5,
|
||||
"min_code_blocks": 0,
|
||||
"max_code_blocks": 3,
|
||||
"error_message": "SYNOPSIS section is mandatory for all manpages"
|
||||
},
|
||||
"DESCRIPTION": {
|
||||
"classification": "required",
|
||||
"heading_level": 2,
|
||||
"position": "after_section_name",
|
||||
"content_instruction": "Detailed explanation of what the command does",
|
||||
"min_paragraphs": 2,
|
||||
"error_message": "DESCRIPTION section is mandatory for all manpages"
|
||||
},
|
||||
"EXAMPLES": {
|
||||
"classification": "recommended",
|
||||
"heading_level": 2,
|
||||
"content_instruction": "Practical usage examples with explanations",
|
||||
"min_code_blocks": 3,
|
||||
"warning_if_missing": "Examples greatly improve manpage usability"
|
||||
},
|
||||
"SEE ALSO": {
|
||||
"classification": "recommended",
|
||||
"heading_level": 2,
|
||||
"content_instruction": "Related commands and documentation references",
|
||||
"warning_if_missing": "Cross-references help users discover related functionality"
|
||||
},
|
||||
"BUGS": {
|
||||
"classification": "optional",
|
||||
"heading_level": 2,
|
||||
"content_instruction": "Known issues and bug reporting information"
|
||||
},
|
||||
"DEPRECATED": {
|
||||
"classification": "discouraged",
|
||||
"heading_level": 2,
|
||||
"warning_if_missing": "Consider moving deprecated content to historical documentation"
|
||||
},
|
||||
"INTERNAL_NOTES": {
|
||||
"classification": "improper",
|
||||
"heading_level": 2,
|
||||
"error_message": "Internal notes must not appear in published manpages"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Validation Behavior
|
||||
|
||||
#### Required Sections
|
||||
|
||||
```json
|
||||
"SYNOPSIS": {"classification": "required"}
|
||||
```
|
||||
|
||||
**Validation**:
|
||||
- Section missing → **ERROR** → `is_valid = False`
|
||||
- Section present → Continue validation
|
||||
- Custom `error_message` used if provided
|
||||
|
||||
#### Recommended Sections
|
||||
|
||||
```json
|
||||
"EXAMPLES": {"classification": "recommended"}
|
||||
```
|
||||
|
||||
**Validation**:
|
||||
- Section missing → **WARNING** → `is_valid = True` (with warnings)
|
||||
- Section present → Continue validation
|
||||
- Custom `warning_if_missing` used if provided
|
||||
|
||||
#### Optional Sections
|
||||
|
||||
```json
|
||||
"BUGS": {"classification": "optional"}
|
||||
```
|
||||
|
||||
**Validation**:
|
||||
- Section missing → No impact
|
||||
- Section present → Continue validation
|
||||
- No messages generated
|
||||
|
||||
#### Discouraged Sections
|
||||
|
||||
```json
|
||||
"DEPRECATED": {"classification": "discouraged"}
|
||||
```
|
||||
|
||||
**Validation**:
|
||||
- Section missing → No impact
|
||||
- Section present → **WARNING** → `is_valid = True` (with warnings)
|
||||
- Custom warning message used if provided
|
||||
|
||||
#### Improper Sections
|
||||
|
||||
```json
|
||||
"INTERNAL_NOTES": {"classification": "improper"}
|
||||
```
|
||||
|
||||
**Validation**:
|
||||
- Section missing → No impact
|
||||
- Section present → **ERROR** → `is_valid = False`
|
||||
- Custom `error_message` used if provided
|
||||
|
||||
---
|
||||
|
||||
## Extension: `x-markitect-content-control`
|
||||
|
||||
### Purpose
|
||||
|
||||
Define content validation rules for document sections including pattern matching, quality metrics, and semantic constraints.
|
||||
|
||||
### Schema Location
|
||||
|
||||
Applied at **root level** or within specific **section properties**.
|
||||
|
||||
### Format
|
||||
|
||||
```json
|
||||
{
|
||||
"x-markitect-content-control": {
|
||||
"section_name": {
|
||||
"required_patterns": ["regex_pattern_1", "regex_pattern_2"],
|
||||
"discouraged_patterns": ["regex_pattern_1"],
|
||||
"forbidden_patterns": ["regex_pattern_1"],
|
||||
"content_quality": {
|
||||
"min_words": integer,
|
||||
"max_words": integer,
|
||||
"readability_target": "technical|general|simple|advanced",
|
||||
"min_sentences": integer,
|
||||
"max_sentences": integer
|
||||
},
|
||||
"content_instructions": ["instruction_1", "instruction_2"],
|
||||
"link_validation": {
|
||||
"check_internal": boolean,
|
||||
"check_external": boolean,
|
||||
"allow_fragments": boolean
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Property Definitions
|
||||
|
||||
#### `required_patterns` (optional)
|
||||
|
||||
Array of regex patterns that MUST appear in section content.
|
||||
|
||||
**Type**: Array of strings (valid regex patterns)
|
||||
**Validation**: ERROR if any pattern missing
|
||||
|
||||
**Example**:
|
||||
```json
|
||||
"required_patterns": [
|
||||
"\\*\\*[a-z-]+\\*\\*", // Bold command name
|
||||
"\\[.*\\]" // Options in brackets
|
||||
]
|
||||
```
|
||||
|
||||
#### `discouraged_patterns` (optional)
|
||||
|
||||
Array of regex patterns that SHOULD NOT appear in content.
|
||||
|
||||
**Type**: Array of strings (valid regex patterns)
|
||||
**Validation**: WARNING if any pattern found
|
||||
|
||||
**Example**:
|
||||
```json
|
||||
"discouraged_patterns": [
|
||||
"TODO",
|
||||
"FIXME",
|
||||
"\\bWIP\\b"
|
||||
]
|
||||
```
|
||||
|
||||
#### `forbidden_patterns` (optional)
|
||||
|
||||
Array of regex patterns that MUST NOT appear in content.
|
||||
|
||||
**Type**: Array of strings (valid regex patterns)
|
||||
**Validation**: ERROR if any pattern found
|
||||
|
||||
**Example**:
|
||||
```json
|
||||
"forbidden_patterns": [
|
||||
"password\\s*=\\s*[\"'].*[\"']", // Hard-coded passwords
|
||||
"api[_-]?key\\s*=\\s*[\"'].*[\"']" // Hard-coded API keys
|
||||
]
|
||||
```
|
||||
|
||||
#### `content_quality` (optional)
|
||||
|
||||
Quality metrics for section content:
|
||||
|
||||
**Sub-properties**:
|
||||
- **`min_words`**: Minimum word count (integer ≥ 0)
|
||||
- **`max_words`**: Maximum word count (integer ≥ min_words)
|
||||
- **`readability_target`**: Target readability level (enum)
|
||||
- `"simple"` - Elementary school level
|
||||
- `"general"` - General audience
|
||||
- `"technical"` - Technical audience
|
||||
- `"advanced"` - Expert/academic level
|
||||
- **`min_sentences`**: Minimum sentence count (integer ≥ 0)
|
||||
- **`max_sentences`**: Maximum sentence count (integer ≥ min_sentences)
|
||||
|
||||
**Example**:
|
||||
```json
|
||||
"content_quality": {
|
||||
"min_words": 50,
|
||||
"max_words": 300,
|
||||
"readability_target": "technical",
|
||||
"min_sentences": 3
|
||||
}
|
||||
```
|
||||
|
||||
#### `content_instructions` (optional)
|
||||
|
||||
Array of human-readable instructions for content creation.
|
||||
|
||||
**Type**: Array of strings
|
||||
**Usage**: Displayed in templates, validation reports, and documentation
|
||||
|
||||
**Example**:
|
||||
```json
|
||||
"content_instructions": [
|
||||
"Show command name in bold",
|
||||
"Include all major options",
|
||||
"Use italic for arguments and placeholders",
|
||||
"Keep syntax examples concise (1-3 lines)"
|
||||
]
|
||||
```
|
||||
|
||||
#### `link_validation` (optional)
|
||||
|
||||
Link checking configuration:
|
||||
|
||||
**Sub-properties**:
|
||||
- **`check_internal`**: Validate internal document links (boolean)
|
||||
- **`check_external`**: Validate external URLs (boolean)
|
||||
- **`allow_fragments`**: Allow fragment-only links like `#section` (boolean)
|
||||
|
||||
**Default**: All false (no link validation)
|
||||
|
||||
**Example**:
|
||||
```json
|
||||
"link_validation": {
|
||||
"check_internal": true,
|
||||
"check_external": false,
|
||||
"allow_fragments": true
|
||||
}
|
||||
```
|
||||
|
||||
### Example: Content Control for API Documentation
|
||||
|
||||
```json
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"title": "API Documentation Schema",
|
||||
"x-markitect-content-control": {
|
||||
"synopsis": {
|
||||
"required_patterns": [
|
||||
"\\*\\*[A-Z]+\\*\\*", // HTTP method in bold
|
||||
"`/api/.*`" // Endpoint path in code
|
||||
],
|
||||
"content_quality": {
|
||||
"min_words": 10,
|
||||
"max_words": 100,
|
||||
"readability_target": "technical"
|
||||
},
|
||||
"content_instructions": [
|
||||
"Start with HTTP method in bold (e.g., **GET**)",
|
||||
"Show endpoint path in code format",
|
||||
"Include brief one-line description"
|
||||
]
|
||||
},
|
||||
"request_parameters": {
|
||||
"required_patterns": [
|
||||
"\\*\\*[a-z_]+\\*\\*.*\\*[A-Za-z]+\\*" // Bold param name with italic type
|
||||
],
|
||||
"content_instructions": [
|
||||
"Use bold for parameter names",
|
||||
"Use italic for parameter types",
|
||||
"Include description for each parameter",
|
||||
"Mark required parameters clearly"
|
||||
]
|
||||
},
|
||||
"description": {
|
||||
"discouraged_patterns": [
|
||||
"TODO",
|
||||
"FIXME",
|
||||
"TBD"
|
||||
],
|
||||
"forbidden_patterns": [
|
||||
"password\\s*=",
|
||||
"secret\\s*=",
|
||||
"token\\s*="
|
||||
],
|
||||
"content_quality": {
|
||||
"min_words": 50,
|
||||
"max_words": 500,
|
||||
"readability_target": "technical",
|
||||
"min_sentences": 3
|
||||
},
|
||||
"link_validation": {
|
||||
"check_internal": true,
|
||||
"check_external": true,
|
||||
"allow_fragments": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Validation Result Structure
|
||||
|
||||
### Enhanced ValidationResult Class
|
||||
|
||||
```python
|
||||
class ValidationResult:
|
||||
"""Result of schema validation with classification support."""
|
||||
|
||||
status: Literal["valid", "valid_with_warnings", "invalid"]
|
||||
errors: List[ValidationError] # Required/improper violations
|
||||
warnings: List[ValidationWarning] # Recommended/discouraged violations
|
||||
suggestions: List[str] # Optional improvements
|
||||
quality_metrics: Dict[str, Any] # Content quality scores
|
||||
```
|
||||
|
||||
### Validation Status Values
|
||||
|
||||
- **`"valid"`**: No errors, no warnings. Document fully conforms.
|
||||
- **`"valid_with_warnings"`**: No errors, but has warnings. Document acceptable but improvable.
|
||||
- **`"invalid"`**: Has errors. Document does not conform to schema.
|
||||
|
||||
### Error Types
|
||||
|
||||
```python
|
||||
class ValidationErrorType(Enum):
|
||||
MISSING_REQUIRED_SECTION = "missing_required_section"
|
||||
IMPROPER_SECTION_PRESENT = "improper_section_present"
|
||||
CONTENT_PATTERN_MISSING = "content_pattern_missing"
|
||||
CONTENT_PATTERN_FORBIDDEN = "content_pattern_forbidden"
|
||||
CONTENT_TOO_SHORT = "content_too_short"
|
||||
CONTENT_TOO_LONG = "content_too_long"
|
||||
INVALID_LINK = "invalid_link"
|
||||
STRUCTURE_MISMATCH = "structure_mismatch"
|
||||
```
|
||||
|
||||
### Warning Types
|
||||
|
||||
```python
|
||||
class ValidationWarningType(Enum):
|
||||
MISSING_RECOMMENDED_SECTION = "missing_recommended_section"
|
||||
DISCOURAGED_SECTION_PRESENT = "discouraged_section_present"
|
||||
CONTENT_PATTERN_DISCOURAGED = "content_pattern_discouraged"
|
||||
CONTENT_QUALITY_BELOW_TARGET = "content_quality_below_target"
|
||||
READABILITY_MISMATCH = "readability_mismatch"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Metaschema Validation
|
||||
|
||||
### Extension Validation Rules
|
||||
|
||||
The MarkiTect metaschema validates these extensions:
|
||||
|
||||
```json
|
||||
{
|
||||
"x-markitect-sections": {
|
||||
"type": "object",
|
||||
"patternProperties": {
|
||||
"^[A-Z][A-Z0-9_ ]*$": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"classification": {
|
||||
"type": "string",
|
||||
"enum": ["required", "recommended", "optional", "discouraged", "improper"]
|
||||
},
|
||||
"heading_level": {
|
||||
"type": "integer",
|
||||
"minimum": 1,
|
||||
"maximum": 6
|
||||
},
|
||||
"position": {
|
||||
"type": "string",
|
||||
"enum": ["after_title", "before_section_name", "after_section_name", "anywhere"]
|
||||
},
|
||||
"content_instruction": {"type": "string"},
|
||||
"min_paragraphs": {"type": "integer", "minimum": 0},
|
||||
"max_paragraphs": {"type": "integer", "minimum": 0},
|
||||
"min_code_blocks": {"type": "integer", "minimum": 0},
|
||||
"max_code_blocks": {"type": "integer", "minimum": 0},
|
||||
"min_lists": {"type": "integer", "minimum": 0},
|
||||
"max_lists": {"type": "integer", "minimum": 0},
|
||||
"warning_if_missing": {"type": "string"},
|
||||
"error_message": {"type": "string"},
|
||||
"alternatives": {
|
||||
"type": "array",
|
||||
"items": {"type": "string"}
|
||||
}
|
||||
},
|
||||
"required": ["classification"]
|
||||
}
|
||||
}
|
||||
},
|
||||
"x-markitect-content-control": {
|
||||
"type": "object",
|
||||
"patternProperties": {
|
||||
"^[a-z][a-z0-9_]*$": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"required_patterns": {
|
||||
"type": "array",
|
||||
"items": {"type": "string", "format": "regex"}
|
||||
},
|
||||
"discouraged_patterns": {
|
||||
"type": "array",
|
||||
"items": {"type": "string", "format": "regex"}
|
||||
},
|
||||
"forbidden_patterns": {
|
||||
"type": "array",
|
||||
"items": {"type": "string", "format": "regex"}
|
||||
},
|
||||
"content_quality": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"min_words": {"type": "integer", "minimum": 0},
|
||||
"max_words": {"type": "integer", "minimum": 0},
|
||||
"readability_target": {
|
||||
"type": "string",
|
||||
"enum": ["simple", "general", "technical", "advanced"]
|
||||
},
|
||||
"min_sentences": {"type": "integer", "minimum": 0},
|
||||
"max_sentences": {"type": "integer", "minimum": 0}
|
||||
}
|
||||
},
|
||||
"content_instructions": {
|
||||
"type": "array",
|
||||
"items": {"type": "string"}
|
||||
},
|
||||
"link_validation": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"check_internal": {"type": "boolean"},
|
||||
"check_external": {"type": "boolean"},
|
||||
"allow_fragments": {"type": "boolean"}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
### Phase 1 Scope
|
||||
|
||||
1. Define and document extension formats ✓
|
||||
2. Update metaschema to validate extensions
|
||||
3. Implement basic classification validation (required/recommended/optional/discouraged/improper)
|
||||
4. Create example schemas demonstrating all features
|
||||
5. Update CLI to report errors vs warnings separately
|
||||
|
||||
### Future Enhancements (Phase 2+)
|
||||
|
||||
- Content pattern matching implementation
|
||||
- Quality metrics calculation
|
||||
- Link validation
|
||||
- Readability scoring
|
||||
- Position constraints enforcement
|
||||
|
||||
---
|
||||
|
||||
## Version History
|
||||
|
||||
- **v1.0 (Draft)** - Initial specification for Phase 1 implementation
|
||||
- `x-markitect-sections` extension defined
|
||||
- `x-markitect-content-control` extension defined
|
||||
- Validation result structure defined
|
||||
- Metaschema validation rules defined
|
||||
|
||||
---
|
||||
|
||||
## References
|
||||
|
||||
- JSON Schema Draft-07: https://json-schema.org/draft-07/schema
|
||||
- MarkiTect Schema Evolution Workplan: `examples/manpages/SCHEMA_EVOLUTION_WORKPLAN.md`
|
||||
- Existing Metaschema: `markitect/schemas/markitect-metaschema.json`
|
||||
- Metaschema Validator: `markitect/metaschema.py`
|
||||
495
docs/user-guides/SCHEMA_REFINEMENT_TOOLS.md
Normal file
495
docs/user-guides/SCHEMA_REFINEMENT_TOOLS.md
Normal file
@@ -0,0 +1,495 @@
|
||||
# Schema Refinement Tools - User Guide
|
||||
|
||||
## Overview
|
||||
|
||||
MarkiTect Phase 2 introduces powerful schema refinement tools to help you analyze and improve JSON schemas for markdown validation. These tools detect rigidity issues and automatically apply fixes to make schemas more flexible and reusable.
|
||||
|
||||
## Quick Start
|
||||
|
||||
```bash
|
||||
# Analyze a schema for rigidity issues
|
||||
markitect schema-analyze examples/manpages/markdown-manpage-schema.json
|
||||
|
||||
# Refine a schema automatically
|
||||
markitect schema-refine examples/manpages/markdown-manpage-schema.json --output refined-schema.json
|
||||
|
||||
# Review each fix interactively
|
||||
markitect schema-refine examples/manpages/markdown-manpage-schema.json --interactive
|
||||
```
|
||||
|
||||
## Commands
|
||||
|
||||
### schema-analyze
|
||||
|
||||
Analyzes a JSON schema to detect rigidity issues and calculate a rigidity score (0-100).
|
||||
|
||||
#### Usage
|
||||
|
||||
```bash
|
||||
markitect schema-analyze <schema-file> [OPTIONS]
|
||||
```
|
||||
|
||||
#### Options
|
||||
|
||||
- `--verbose`, `-v`: Show detailed analysis with current and suggested values
|
||||
|
||||
#### Examples
|
||||
|
||||
```bash
|
||||
# Basic analysis
|
||||
markitect schema-analyze schema.json
|
||||
|
||||
# Verbose output with details
|
||||
markitect schema-analyze schema.json --verbose
|
||||
```
|
||||
|
||||
#### Output
|
||||
|
||||
The analyzer provides:
|
||||
|
||||
- **Rigidity Score** (0-100): Higher scores indicate more rigid schemas
|
||||
- 0-40: LOW - Flexible, good design
|
||||
- 41-70: MEDIUM - Some rigidity detected
|
||||
- 71-100: HIGH - Very rigid, needs refinement
|
||||
|
||||
- **Phase 1 Features**: Checks for classification system and content control
|
||||
- **Issue Count**: Breakdown by severity (Errors, Warnings, Info)
|
||||
- **Detected Issues**: List of problems with suggestions
|
||||
|
||||
#### Exit Codes
|
||||
|
||||
- `0`: Schema is flexible (score ≤ 50)
|
||||
- `1`: Schema is rigid (score > 50)
|
||||
- `2`: Error occurred
|
||||
|
||||
### schema-refine
|
||||
|
||||
Automatically refines rigid schemas by applying fixes for detected issues.
|
||||
|
||||
#### Usage
|
||||
|
||||
```bash
|
||||
markitect schema-refine <schema-file> [OPTIONS]
|
||||
```
|
||||
|
||||
#### Options
|
||||
|
||||
- `--output`, `-o PATH`: Output file (default: overwrite input file)
|
||||
- `--loosen-counts`: Convert exact counts to flexible ranges (default: enabled)
|
||||
- `--no-loosen-counts`: Disable count loosening
|
||||
- `--round-numbers`: Round overly specific numbers (default: enabled)
|
||||
- `--no-round-numbers`: Disable number rounding
|
||||
- `--migrate-deprecated`: Document deprecated extensions (default: disabled)
|
||||
- `--dry-run`: Show changes without applying them
|
||||
- `--interactive`, `-i`: Prompt for each refinement interactively
|
||||
|
||||
#### Examples
|
||||
|
||||
```bash
|
||||
# Refine schema in place
|
||||
markitect schema-refine schema.json
|
||||
|
||||
# Preview changes without applying
|
||||
markitect schema-refine schema.json --dry-run
|
||||
|
||||
# Save refined schema to new file
|
||||
markitect schema-refine schema.json --output refined-schema.json
|
||||
|
||||
# Review each fix interactively
|
||||
markitect schema-refine schema.json --interactive
|
||||
|
||||
# Disable specific refinements
|
||||
markitect schema-refine schema.json --no-loosen-counts
|
||||
```
|
||||
|
||||
#### Refinement Actions
|
||||
|
||||
The refiner automatically applies these fixes:
|
||||
|
||||
1. **Exact Count Loosening**: Converts exact counts to flexible ranges
|
||||
- Before: `"minItems": 5, "maxItems": 5`
|
||||
- After: `"minItems": 3, "maxItems": 10`
|
||||
|
||||
2. **Const Value Conversion**: Replaces exact value constraints with ranges
|
||||
- Before: `"const": 1`
|
||||
- After: `"minimum": 0, "maximum": 2`
|
||||
|
||||
3. **Number Rounding**: Rounds overly specific numbers
|
||||
- Before: `"minItems": 73`
|
||||
- After: `"minItems": 70`
|
||||
|
||||
4. **Range Widening**: Expands narrow integer ranges
|
||||
- Before: `"minimum": 5, "maximum": 6`
|
||||
- After: `"minimum": 0, "maximum": 11`
|
||||
|
||||
#### Exit Codes
|
||||
|
||||
- `0`: Success with changes applied
|
||||
- `1`: Success but no changes needed
|
||||
- `2`: Error occurred
|
||||
|
||||
## Issue Types
|
||||
|
||||
### Exact Count (WARNING)
|
||||
|
||||
**Problem**: Schema requires exact number of items, leaving no flexibility.
|
||||
|
||||
**Example**:
|
||||
```json
|
||||
{
|
||||
"type": "array",
|
||||
"minItems": 5,
|
||||
"maxItems": 5
|
||||
}
|
||||
```
|
||||
|
||||
**Fix**: Convert to a range
|
||||
```json
|
||||
{
|
||||
"type": "array",
|
||||
"minItems": 3,
|
||||
"maxItems": 10
|
||||
}
|
||||
```
|
||||
|
||||
### Const Value (WARNING)
|
||||
|
||||
**Problem**: Property must have exact value.
|
||||
|
||||
**Example**:
|
||||
```json
|
||||
{
|
||||
"type": "integer",
|
||||
"const": 1
|
||||
}
|
||||
```
|
||||
|
||||
**Fix**: Replace with range for numeric values
|
||||
```json
|
||||
{
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"maximum": 2
|
||||
}
|
||||
```
|
||||
|
||||
### Overly Specific Numbers (INFO)
|
||||
|
||||
**Problem**: Numbers are too specific (like 73 instead of 70).
|
||||
|
||||
**Example**:
|
||||
```json
|
||||
{
|
||||
"type": "array",
|
||||
"minItems": 73
|
||||
}
|
||||
```
|
||||
|
||||
**Fix**: Round to nearest 10
|
||||
```json
|
||||
{
|
||||
"type": "array",
|
||||
"minItems": 70
|
||||
}
|
||||
```
|
||||
|
||||
### No Flexibility (INFO)
|
||||
|
||||
**Problem**: Integer range is too narrow.
|
||||
|
||||
**Example**:
|
||||
```json
|
||||
{
|
||||
"type": "integer",
|
||||
"minimum": 5,
|
||||
"maximum": 6
|
||||
}
|
||||
```
|
||||
|
||||
**Fix**: Widen the range
|
||||
```json
|
||||
{
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"maximum": 11
|
||||
}
|
||||
```
|
||||
|
||||
### Missing Classifications (INFO)
|
||||
|
||||
**Problem**: Schema doesn't use the Phase 1 classification system.
|
||||
|
||||
**Suggestion**: Add `x-markitect-sections` to classify sections as required/recommended/optional/discouraged/improper.
|
||||
|
||||
### Missing Content Control (INFO)
|
||||
|
||||
**Problem**: Schema lacks content validation patterns and quality metrics.
|
||||
|
||||
**Suggestion**: Add `x-markitect-content-control` for pattern validation and quality requirements.
|
||||
|
||||
### Deprecated Extensions (WARNING)
|
||||
|
||||
**Problem**: Schema uses old extension format.
|
||||
|
||||
**Example**: `x-markitect-required-sections`
|
||||
|
||||
**Suggestion**: Migrate to `x-markitect-sections` with classification system.
|
||||
|
||||
## Workflows
|
||||
|
||||
### Basic Workflow: Analyze and Refine
|
||||
|
||||
1. **Analyze** your schema to understand issues:
|
||||
```bash
|
||||
markitect schema-analyze my-schema.json --verbose
|
||||
```
|
||||
|
||||
2. **Preview** refinements before applying:
|
||||
```bash
|
||||
markitect schema-refine my-schema.json --dry-run
|
||||
```
|
||||
|
||||
3. **Apply** refinements:
|
||||
```bash
|
||||
markitect schema-refine my-schema.json --output my-schema-refined.json
|
||||
```
|
||||
|
||||
4. **Verify** improvements:
|
||||
```bash
|
||||
markitect schema-analyze my-schema-refined.json
|
||||
```
|
||||
|
||||
### Interactive Workflow
|
||||
|
||||
For fine-grained control, use interactive mode:
|
||||
|
||||
```bash
|
||||
markitect schema-refine my-schema.json --interactive
|
||||
```
|
||||
|
||||
The tool will:
|
||||
1. Show each detected issue
|
||||
2. Display current and suggested values
|
||||
3. Prompt for confirmation (y/N/q)
|
||||
4. Apply only approved fixes
|
||||
|
||||
Example session:
|
||||
```
|
||||
Issue 1/4
|
||||
Type: exact_count
|
||||
Path: properties.headings.level_1
|
||||
Array 'level_1' requires exactly 1 items
|
||||
Suggestion: Use a range like minItems: 0, maxItems: 6
|
||||
Current: {"minItems": 1, "maxItems": 1}
|
||||
Suggested: {"minItems": 0, "maxItems": 6}
|
||||
|
||||
Apply this fix? [y/N/q]: y
|
||||
✓ Applied
|
||||
```
|
||||
|
||||
### CI/CD Integration
|
||||
|
||||
Use exit codes to enforce schema quality in your pipeline:
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
|
||||
# Analyze schema and fail if rigid
|
||||
if ! markitect schema-analyze schema.json; then
|
||||
echo "Schema is too rigid (score > 50)"
|
||||
echo "Run: markitect schema-refine schema.json"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Schema quality check passed"
|
||||
```
|
||||
|
||||
### Schema Migration Workflow
|
||||
|
||||
Migrating from old format to Phase 1:
|
||||
|
||||
1. **Analyze** to identify deprecated extensions:
|
||||
```bash
|
||||
markitect schema-analyze old-schema.json
|
||||
```
|
||||
|
||||
2. **Document** deprecated extensions:
|
||||
```bash
|
||||
markitect schema-refine old-schema.json --migrate-deprecated
|
||||
```
|
||||
|
||||
3. **Manually migrate** to new format (automatic migration not implemented due to complexity)
|
||||
|
||||
## Best Practices
|
||||
|
||||
### When to Use schema-analyze
|
||||
|
||||
- Before committing schemas to version control
|
||||
- During code review to ensure quality
|
||||
- When creating new schemas from examples
|
||||
- To understand why a schema fails validation
|
||||
|
||||
### When to Use schema-refine
|
||||
|
||||
- After auto-generating schemas from documents
|
||||
- When inheriting legacy schemas
|
||||
- To quickly fix common rigidity issues
|
||||
- Before publishing schemas for reuse
|
||||
|
||||
### When to Use --interactive
|
||||
|
||||
- When you need fine-grained control
|
||||
- For schemas with domain-specific requirements
|
||||
- When learning about schema design
|
||||
- To review fixes before applying
|
||||
|
||||
### Recommended Settings
|
||||
|
||||
For most use cases:
|
||||
```bash
|
||||
# Balanced refinement (default)
|
||||
markitect schema-refine schema.json
|
||||
|
||||
# Conservative (preserve more constraints)
|
||||
markitect schema-refine schema.json --no-round-numbers
|
||||
|
||||
# Aggressive (maximum flexibility)
|
||||
markitect schema-refine schema.json --loosen-counts --round-numbers
|
||||
```
|
||||
|
||||
## Understanding Rigidity Scores
|
||||
|
||||
The rigidity score is calculated by weighting detected issues:
|
||||
|
||||
| Issue Type | Weight |
|
||||
|------------|--------|
|
||||
| Exact Count | 15 |
|
||||
| Overly Specific | 10 |
|
||||
| No Flexibility | 8 |
|
||||
| Missing Classifications | 5 |
|
||||
| Deprecated Extensions | 5 |
|
||||
| Missing Content Control | 3 |
|
||||
|
||||
**Score Interpretation**:
|
||||
- **0-20**: Excellent - Well-designed, flexible schema
|
||||
- **21-40**: Good - Minor improvements possible
|
||||
- **41-60**: Fair - Moderate rigidity, refinement recommended
|
||||
- **61-80**: Poor - Significant rigidity, refinement needed
|
||||
- **81-100**: Very Poor - Highly rigid, manual review recommended
|
||||
|
||||
## Integration Examples
|
||||
|
||||
### Git Pre-commit Hook
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
# .git/hooks/pre-commit
|
||||
|
||||
SCHEMAS=$(git diff --cached --name-only --diff-filter=ACM | grep '\.json$')
|
||||
|
||||
for schema in $SCHEMAS; do
|
||||
if markitect schema-analyze "$schema" 2>&1 | grep -q "RIGID"; then
|
||||
echo "Error: $schema is too rigid"
|
||||
echo "Run: markitect schema-refine $schema"
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
```
|
||||
|
||||
### Makefile Target
|
||||
|
||||
```makefile
|
||||
.PHONY: check-schemas
|
||||
check-schemas:
|
||||
@for schema in schemas/*.json; do \
|
||||
echo "Checking $$schema..."; \
|
||||
markitect schema-analyze $$schema || exit 1; \
|
||||
done
|
||||
|
||||
.PHONY: refine-schemas
|
||||
refine-schemas:
|
||||
@for schema in schemas/*.json; do \
|
||||
echo "Refining $$schema..."; \
|
||||
markitect schema-refine $$schema; \
|
||||
done
|
||||
```
|
||||
|
||||
### Python Integration
|
||||
|
||||
```python
|
||||
import subprocess
|
||||
import json
|
||||
|
||||
def analyze_schema(schema_path):
|
||||
"""Analyze a schema and return rigidity score."""
|
||||
result = subprocess.run(
|
||||
["markitect", "schema-analyze", schema_path],
|
||||
capture_output=True,
|
||||
text=True
|
||||
)
|
||||
|
||||
# Parse output for score
|
||||
for line in result.stdout.split('\n'):
|
||||
if 'Rigidity Score:' in line:
|
||||
score = int(line.split(':')[1].split('/')[0].strip())
|
||||
return score
|
||||
return None
|
||||
|
||||
def refine_schema(schema_path, output_path):
|
||||
"""Refine a schema and save to output path."""
|
||||
result = subprocess.run(
|
||||
["markitect", "schema-refine", schema_path, "-o", output_path],
|
||||
capture_output=True,
|
||||
text=True
|
||||
)
|
||||
return result.returncode == 0
|
||||
|
||||
# Usage
|
||||
score = analyze_schema("schema.json")
|
||||
if score > 50:
|
||||
print(f"Schema is rigid (score: {score})")
|
||||
refine_schema("schema.json", "schema-refined.json")
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Schema Not Found
|
||||
|
||||
**Error**: `Error: Schema file not found: schema.json`
|
||||
|
||||
**Solution**: Check file path and ensure file exists.
|
||||
|
||||
### Invalid JSON
|
||||
|
||||
**Error**: `Error: Invalid JSON in schema file`
|
||||
|
||||
**Solution**: Validate JSON syntax using `jsonlint` or similar tool.
|
||||
|
||||
### No Changes Applied
|
||||
|
||||
**Output**: `No refinements needed - schema is already flexible`
|
||||
|
||||
**Reason**: Schema doesn't have any detectable rigidity issues or has rigidity score < 50.
|
||||
|
||||
**Action**: Use `--verbose` to see all issues including INFO level.
|
||||
|
||||
### Refinement Broke Schema
|
||||
|
||||
**Problem**: Refined schema is too permissive.
|
||||
|
||||
**Solution**:
|
||||
1. Use `--interactive` to selectively apply fixes
|
||||
2. Use `--no-loosen-counts` or `--no-round-numbers` to preserve constraints
|
||||
3. Manually adjust ranges after refinement
|
||||
|
||||
## See Also
|
||||
|
||||
- [Schema Extensions Specification](../specifications/schema-extensions-spec.md) - Complete Phase 1 specification
|
||||
- [Schema Evolution Workplan](../../examples/manpages/SCHEMA_EVOLUTION_WORKPLAN.md) - Roadmap for schema features
|
||||
- [Manpage Example](../../examples/manpages/README.md) - Complete example demonstrating schema validation
|
||||
|
||||
## Support
|
||||
|
||||
For issues, questions, or feature requests:
|
||||
- GitHub Issues: https://github.com/anthropics/markitect/issues
|
||||
- Documentation: https://github.com/anthropics/markitect/docs
|
||||
158
examples/design-patterns/CopyFirstMigration.md
Normal file
158
examples/design-patterns/CopyFirstMigration.md
Normal file
@@ -0,0 +1,158 @@
|
||||
# Design Principle: Copy First Migration
|
||||
|
||||
## Meta
|
||||
- **Name:** Copy First Migration
|
||||
- **ShortName:** CopyFirst
|
||||
- **Version:** 0.1
|
||||
- **Status:** Draft
|
||||
- **Tags:** refactoring, migration, safety, testing, legacy
|
||||
- **RelatedPrinciples:** Don’t Repeat Yourself, Safe Refactoring, Test Pyramid, Capability-Based Testing
|
||||
|
||||
---
|
||||
|
||||
## Intent
|
||||
Enable safe refactoring and structural migration of codebases by preserving
|
||||
existing, working functionality until the new implementation is fully verified.
|
||||
|
||||
This principle prioritizes **reversibility, confidence, and continuity** over
|
||||
speed or elegance.
|
||||
|
||||
---
|
||||
|
||||
## CoreStatement
|
||||
Never move code directly; always copy first and delete only after verified
|
||||
behavioral equivalence is established.
|
||||
|
||||
---
|
||||
|
||||
## Scope
|
||||
|
||||
### InScope
|
||||
- Large-scale refactors or directory restructurings
|
||||
- Technology or language migrations (e.g. JS → new JS layout, JS → Python integration)
|
||||
- Legacy code stabilization
|
||||
- Safety-critical or business-critical systems
|
||||
- Situations with incomplete test coverage
|
||||
|
||||
### OutOfScope
|
||||
- Greenfield development
|
||||
- Trivial refactors with full and trusted test coverage
|
||||
- One-off throwaway scripts
|
||||
- Performance-driven rewrites where duplication is unacceptable
|
||||
|
||||
---
|
||||
|
||||
## InterpretationGuidelines
|
||||
|
||||
### What “Copy First” Means
|
||||
- The original code remains untouched and functional
|
||||
- The new version is treated as **experimental until proven**
|
||||
- Deletion is a **final, explicit act**, not an implicit side effect
|
||||
|
||||
### Common Misinterpretations
|
||||
- “This is inefficient because it duplicates code”
|
||||
→ Duplication is intentional and temporary
|
||||
- “Moving files is faster”
|
||||
→ Speed is not the optimization target here
|
||||
- “Tests alone are enough”
|
||||
→ Tests are necessary but not sufficient without behavioral comparison
|
||||
|
||||
---
|
||||
|
||||
## DetectionHeuristics
|
||||
|
||||
### Structural Signals
|
||||
- Files or modules being relocated across directories or packages
|
||||
- Parallel implementations during migration
|
||||
- Introduction of a new architectural boundary
|
||||
|
||||
### Semantic Signals
|
||||
- Code paths that must remain behaviorally identical
|
||||
- Business rules with high regression risk
|
||||
- Legacy logic that is poorly documented but relied upon
|
||||
|
||||
### Change-Cost Signals
|
||||
- Rollbacks are expensive or disruptive
|
||||
- Failures would impact production or customers
|
||||
- Migration spans multiple commits or teams
|
||||
|
||||
---
|
||||
|
||||
## DiagnosticQuestions
|
||||
1. What breaks if this migration is wrong?
|
||||
2. Do we have a known-good reference implementation?
|
||||
3. Can both old and new code paths run in parallel?
|
||||
4. How quickly can we revert if a defect is found?
|
||||
5. What is the minimal proof of behavioral equivalence?
|
||||
|
||||
---
|
||||
|
||||
## RecommendedActions
|
||||
|
||||
### Low-Risk Actions
|
||||
- Copy files to the new location instead of moving
|
||||
- Preserve original imports and entry points
|
||||
- Add logging or tracing for comparison
|
||||
|
||||
### Medium-Risk Actions
|
||||
- Introduce dual-track execution (old + new)
|
||||
- Add integration tests targeting both implementations
|
||||
- Compare outputs, side effects, and error behavior
|
||||
|
||||
### High-Risk Actions
|
||||
- Switch production usage to the new implementation
|
||||
- Remove old code only after full verification
|
||||
- Collapse duplicated paths once confidence is established
|
||||
|
||||
---
|
||||
|
||||
## AcceptanceCriteria
|
||||
- Original code remains functional until final removal
|
||||
- New code passes all existing tests
|
||||
- New integration tests validate identical behavior
|
||||
- Dual-track comparisons show no regressions
|
||||
- Deletion of old code is deliberate and reversible up to the final step
|
||||
|
||||
---
|
||||
|
||||
## AntiPatterns
|
||||
- Moving files directly without a fallback
|
||||
- Refactoring and migration in a single irreversible step
|
||||
- Deleting “unused” code before equivalence is proven
|
||||
- Assuming test parity guarantees behavioral parity
|
||||
- Big-bang migrations without rollback paths
|
||||
|
||||
---
|
||||
|
||||
## Tradeoffs
|
||||
Applying Copy First Migration intentionally:
|
||||
- Introduces temporary duplication
|
||||
- Increases short-term codebase size
|
||||
- Slows perceived progress
|
||||
|
||||
These costs are justified by dramatically reduced risk and higher confidence
|
||||
during complex migrations.
|
||||
|
||||
---
|
||||
|
||||
## AgentUsage
|
||||
|
||||
### When to Apply This Lens
|
||||
- During directory, module, or architecture migrations
|
||||
- When refactoring legacy or poorly understood code
|
||||
- When safety and uptime matter more than speed
|
||||
- When rollback must remain possible at all times
|
||||
|
||||
### When to Suspend This Lens
|
||||
- In greenfield projects
|
||||
- When full test coverage and confidence already exist
|
||||
- For trivial mechanical refactors
|
||||
|
||||
### Expected Agent Output
|
||||
- Identification of migration boundaries
|
||||
- Copy-first migration plan with explicit stages
|
||||
- Test strategy (unit, integration, dual-track)
|
||||
- Rollback points and deletion criteria
|
||||
- Clear signal for when old code may be removed
|
||||
|
||||
xxx
|
||||
135
examples/design-patterns/DesignPrincipleSchema.json
Normal file
135
examples/design-patterns/DesignPrincipleSchema.json
Normal file
@@ -0,0 +1,135 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"type": "object",
|
||||
"title": "Schema for DesignPrinciples",
|
||||
"description": "JSON schema describing the markdown structure of OperationalKnowledge DesignPrinciples",
|
||||
"properties": {
|
||||
"headings": {
|
||||
"type": "object",
|
||||
"description": "Document heading structure",
|
||||
"properties": {
|
||||
"level_1": {
|
||||
"type": "array",
|
||||
"description": "Headings at level 1",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"content": {
|
||||
"type": "string"
|
||||
},
|
||||
"level": {
|
||||
"type": "integer"
|
||||
},
|
||||
"position": {
|
||||
"type": "integer"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"content",
|
||||
"level"
|
||||
]
|
||||
},
|
||||
"minItems": 1,
|
||||
"maxItems": 1
|
||||
},
|
||||
"level_2": {
|
||||
"type": "array",
|
||||
"description": "Headings at level 2",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"content": {
|
||||
"type": "string"
|
||||
},
|
||||
"level": {
|
||||
"type": "integer"
|
||||
},
|
||||
"position": {
|
||||
"type": "integer"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"content",
|
||||
"level"
|
||||
]
|
||||
},
|
||||
"minItems": 4,
|
||||
"maxItems": 12
|
||||
},
|
||||
"level_3": {
|
||||
"type": "array",
|
||||
"description": "Headings at level 3",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"content": {
|
||||
"type": "string"
|
||||
},
|
||||
"level": {
|
||||
"type": "integer"
|
||||
},
|
||||
"position": {
|
||||
"type": "integer"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"content",
|
||||
"level"
|
||||
]
|
||||
},
|
||||
"minItems": 0,
|
||||
"maxItems": 40
|
||||
}
|
||||
}
|
||||
},
|
||||
"paragraphs": {
|
||||
"type": "array",
|
||||
"description": "Text paragraphs",
|
||||
"minItems": 8,
|
||||
"maxItems": 120
|
||||
},
|
||||
"lists": {
|
||||
"type": "array",
|
||||
"description": "Lists (ordered and unordered)",
|
||||
"minItems": 0,
|
||||
"maxItems": 20
|
||||
},
|
||||
"emphasis": {
|
||||
"type": "array",
|
||||
"description": "Text emphasis (bold, italic)",
|
||||
"minItems": 0,
|
||||
"maxItems": 120
|
||||
},
|
||||
"metadata": {
|
||||
"type": "object",
|
||||
"description": "Document structure metadata",
|
||||
"properties": {
|
||||
"total_elements": {
|
||||
"type": "integer",
|
||||
"const": 115
|
||||
},
|
||||
"structure_types": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": "All structural element types found",
|
||||
"const": [
|
||||
"paragraph_close",
|
||||
"heading_close",
|
||||
"hr",
|
||||
"bullet_list_open",
|
||||
"paragraph_open",
|
||||
"heading_open",
|
||||
"ordered_list_open",
|
||||
"ordered_list_close",
|
||||
"inline",
|
||||
"list_item_close",
|
||||
"list_item_open",
|
||||
"bullet_list_close"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
160
examples/design-patterns/DontRepeatYourself.md
Normal file
160
examples/design-patterns/DontRepeatYourself.md
Normal file
@@ -0,0 +1,160 @@
|
||||
# Design Principle: Don’t Repeat Yourself (DRY)
|
||||
|
||||
## Meta
|
||||
- **Name:** Don’t Repeat Yourself
|
||||
- **ShortName:** DRY
|
||||
- **Version:** 0.1
|
||||
- **Status:** Stable
|
||||
- **Tags:** maintainability, refactoring, architecture, quality
|
||||
- **RelatedPrinciples:** Single Responsibility, YAGNI, Separation of Concerns
|
||||
|
||||
---
|
||||
|
||||
## Intent
|
||||
Reduce maintenance cost and behavioral drift by ensuring that each piece of
|
||||
knowledge, rule, or decision logic has a single authoritative representation
|
||||
in the codebase.
|
||||
|
||||
---
|
||||
|
||||
## CoreStatement
|
||||
A codebase violates DRY when the same knowledge is expressed in multiple places
|
||||
such that a change would require edits in more than one location or risks
|
||||
inconsistent behavior.
|
||||
|
||||
---
|
||||
|
||||
## Scope
|
||||
|
||||
### InScope
|
||||
- Business rules and decision logic
|
||||
- Algorithms and validation logic
|
||||
- Data schemas, DTOs, and field definitions
|
||||
- Configuration values and feature flags
|
||||
- Repeated workflows or orchestration logic
|
||||
- Test setup and invariant test scenarios
|
||||
|
||||
### OutOfScope
|
||||
- Superficial textual similarity without shared meaning
|
||||
- Intentional duplication for isolation or clarity
|
||||
- Early-stage exploratory code where abstractions are not yet clear
|
||||
- Performance-driven duplication with explicit justification
|
||||
|
||||
---
|
||||
|
||||
## InterpretationGuidelines
|
||||
|
||||
### What “Repeat” Means
|
||||
DRY is about **duplication of knowledge**, not duplication of text.
|
||||
|
||||
Examples of knowledge duplication:
|
||||
- The same validation rule implemented in multiple services
|
||||
- Identical conditional logic controlling the same behavior
|
||||
- The same data structure defined independently in multiple modules
|
||||
|
||||
### Common Misinterpretations
|
||||
- “Any repeated code is bad” (false)
|
||||
- “DRY means maximum abstraction” (false)
|
||||
- “Utility modules automatically improve DRY” (often false)
|
||||
|
||||
---
|
||||
|
||||
## DetectionHeuristics
|
||||
|
||||
### Structural Signals
|
||||
- Functions with highly similar bodies and signatures
|
||||
- Repeated constants, strings, regexes, or SQL fragments
|
||||
- Parallel modules with mirrored internal structure
|
||||
|
||||
### Semantic Signals
|
||||
- Identical error messages or validation rules in different layers
|
||||
- Repeated mapping logic between the same concepts
|
||||
- Copy-paste variations differing only in naming
|
||||
|
||||
### Change-Cost Signals
|
||||
- A requirement change touches multiple files for the same reason
|
||||
- Fixes applied in one location but missing in others
|
||||
- Tests failing inconsistently after partial updates
|
||||
|
||||
---
|
||||
|
||||
## DiagnosticQuestions
|
||||
1. Is this duplication representing the same rule or policy?
|
||||
2. If this rule changes, how many places must be updated?
|
||||
3. Is the duplicated logic stable or likely to evolve?
|
||||
4. Are the differences intentional or accidental?
|
||||
5. Where is the natural “source of truth” for this knowledge?
|
||||
6. Would abstraction reduce or increase cognitive load?
|
||||
|
||||
---
|
||||
|
||||
## RecommendedActions
|
||||
|
||||
### Low-Risk Refactors
|
||||
- Extract constants or configuration values
|
||||
- Centralize literals and error messages
|
||||
- Introduce shared test fixtures or helpers
|
||||
|
||||
### Medium-Risk Refactors
|
||||
- Extract pure helper functions
|
||||
- Introduce shared domain services or modules
|
||||
- Unify schema/type definitions
|
||||
|
||||
### High-Risk Refactors
|
||||
- Introduce strategy/template patterns
|
||||
- Merge parallel subsystems
|
||||
- Redesign domain boundaries to align ownership of rules
|
||||
|
||||
---
|
||||
|
||||
## AcceptanceCriteria
|
||||
- Each rule or behavior has a single authoritative implementation
|
||||
- Required changes affect fewer locations than before
|
||||
- Naming reflects domain meaning, not technical convenience
|
||||
- Tests pass without behavior regression
|
||||
- Coupling does not increase unintentionally
|
||||
|
||||
---
|
||||
|
||||
## AntiPatterns
|
||||
- “God” utility modules with unrelated helpers
|
||||
- Over-generalized abstractions with many parameters
|
||||
- Shared code across domains that should evolve independently
|
||||
- Premature abstraction of coincidental similarities
|
||||
- Hiding meaningful differences behind generic interfaces
|
||||
|
||||
---
|
||||
|
||||
## Tradeoffs
|
||||
Applying DRY may:
|
||||
- Increase indirection
|
||||
- Reduce local readability
|
||||
- Introduce coupling between modules
|
||||
|
||||
These costs are acceptable only when outweighed by reduced change cost
|
||||
and increased behavioral consistency.
|
||||
|
||||
---
|
||||
|
||||
## AgentUsage
|
||||
|
||||
### When to Apply This Lens
|
||||
- During refactoring or maintenance work
|
||||
- When change requests repeatedly touch similar code
|
||||
- When bugs recur due to partial updates
|
||||
- During architectural consolidation
|
||||
|
||||
### When to Suspend This Lens
|
||||
- During early exploration or prototyping
|
||||
- When future variability is unclear
|
||||
- When isolation is more valuable than reuse
|
||||
|
||||
### Expected Agent Output
|
||||
- Identified DRY violations with locations
|
||||
- Rationale for why duplication matters
|
||||
- Volatility assessment (stable vs evolving)
|
||||
- Recommended refactor type and target
|
||||
- Risk notes and minimal patch sequence
|
||||
|
||||
xxx
|
||||
|
||||
387
examples/manpages/README.md
Normal file
387
examples/manpages/README.md
Normal file
@@ -0,0 +1,387 @@
|
||||
# Unix Manpage Schema Validation Example
|
||||
|
||||
This example demonstrates MarkiTect's schema validation system by creating a self-validating documentation set: a schema that defines Unix manpage structure and a comprehensive manual about schema validation that validates against its own schema definition.
|
||||
|
||||
## Overview
|
||||
|
||||
This example showcases the "dogfooding" principle - using MarkiTect's schema validation to document schema validation itself. It demonstrates:
|
||||
|
||||
- **Schema-driven documentation** - Defining document structure with JSON Schema
|
||||
- **Self-validation** - The manual validates against the manpage schema it demonstrates
|
||||
- **Reusable patterns** - The manpage schema can validate any Unix-style manual page
|
||||
- **Complete workflow** - From schema creation through validation and refinement
|
||||
|
||||
## Files in This Example
|
||||
|
||||
### Schema File
|
||||
|
||||
The manpage schema is now managed in MarkiTect's schema registry:
|
||||
- **Schema Name**: `manpage-schema-v1.0.md`
|
||||
- **Location**: `markitect/schemas/manpage-schema-v1.0.md`
|
||||
- **Format**: Markdown with embedded JSON (following schema-of-schemas standard)
|
||||
|
||||
This schema defines the structure of Unix-style manual pages written in Markdown.
|
||||
|
||||
**Key Features:**
|
||||
- Validates H1 title format: `command(section) - description`
|
||||
- Requires SYNOPSIS and DESCRIPTION sections
|
||||
- Validates heading hierarchy (H1, H2, H3, H4)
|
||||
- Ensures presence of code examples, paragraphs, and emphasis
|
||||
- Includes custom `x-markitect-*` extensions for manpage conventions
|
||||
|
||||
**Schema Requirements:**
|
||||
- Exactly 1 H1 heading (document title)
|
||||
- 3-30 H2 headings (major sections)
|
||||
- 0-50 H3 headings (subsections)
|
||||
- 5-500 paragraphs (content)
|
||||
- 1-50 code blocks (examples)
|
||||
- 10-500 emphasis elements (commands/arguments)
|
||||
|
||||
### `markdown-schema-validation.1.md`
|
||||
|
||||
A comprehensive manual page (section 7) documenting MarkiTect's markdown schema validation system.
|
||||
|
||||
**Sections Include:**
|
||||
- SYNOPSIS - Command syntax reference
|
||||
- DESCRIPTION - How schema validation works
|
||||
- SCHEMA STRUCTURE - JSON Schema format details
|
||||
- COMMANDS - Schema management and validation commands
|
||||
- WORKFLOW - Step-by-step validation workflows
|
||||
- VALIDATION RULES - What schemas validate
|
||||
- ERROR HANDLING - Understanding validation errors
|
||||
- SCHEMA DESIGN - Best practices and anti-patterns
|
||||
- INTEGRATION - CI/CD, git hooks, build systems
|
||||
- EXAMPLES - Practical usage demonstrations
|
||||
- Plus standard manpage sections: FILES, EXIT STATUS, ENVIRONMENT, SEE ALSO, etc.
|
||||
|
||||
**Statistics:**
|
||||
- 19 H2 sections
|
||||
- 24 H3 subsections
|
||||
- 147 paragraphs
|
||||
- 23 code examples
|
||||
- 105 emphasis markers
|
||||
|
||||
## Running the Example
|
||||
|
||||
### 1. List Available Schemas
|
||||
|
||||
View all registered schemas (including the manpage schema):
|
||||
|
||||
```bash
|
||||
markitect schema-list
|
||||
```
|
||||
|
||||
You should see `manpage-schema-v1.0.md` listed with a number.
|
||||
|
||||
### 2. Validate the Manual Against the Schema
|
||||
|
||||
Verify that the manual conforms to the manpage schema using the new multi-schema validation:
|
||||
|
||||
```bash
|
||||
cd examples/manpages
|
||||
|
||||
# Validate by schema filename (from registry)
|
||||
markitect schema-validate manpage-schema-v1.0.md
|
||||
|
||||
# Or validate by number (if schema is #2 in the list)
|
||||
markitect schema-validate 2
|
||||
|
||||
# Or validate a specific document file
|
||||
markitect validate markdown-schema-validation.1.md \
|
||||
--schema manpage-schema-v1.0.md
|
||||
```
|
||||
|
||||
Expected output: ✅ **VALID** - Document structure matches schema requirements
|
||||
|
||||
### 3. Show Detailed Validation
|
||||
|
||||
See detailed validation information:
|
||||
|
||||
```bash
|
||||
markitect schema-validate manpage-schema-v1.0.md --detailed-errors
|
||||
```
|
||||
|
||||
### 4. Validate Multiple Schemas
|
||||
|
||||
Validate all registered schemas at once:
|
||||
|
||||
```bash
|
||||
# Validate all schemas
|
||||
markitect schema-validate --all
|
||||
|
||||
# Validate a range of schemas
|
||||
markitect schema-validate 1-3
|
||||
|
||||
# Validate specific schemas
|
||||
markitect schema-validate 1,3,5
|
||||
```
|
||||
|
||||
### 5. Examine the Schema
|
||||
|
||||
View the manpage schema in markdown format:
|
||||
|
||||
```bash
|
||||
markitect schema-get manpage-schema-v1.0.md
|
||||
|
||||
# Or view the file directly
|
||||
cat ../../markitect/schemas/manpage-schema-v1.0.md
|
||||
```
|
||||
|
||||
### 6. Validate Other Manpages
|
||||
|
||||
Use the schema to validate other manual pages in the project:
|
||||
|
||||
```bash
|
||||
# Validate using schema name from registry
|
||||
markitect validate ../../docs/manuals/markitect.1.md \
|
||||
--schema manpage-schema-v1.0.md
|
||||
```
|
||||
|
||||
## What This Example Demonstrates
|
||||
|
||||
### 1. Schema-Driven Documentation
|
||||
|
||||
The manpage schema defines what a valid Unix manual page looks like:
|
||||
|
||||
- Required structural elements (title, synopsis, description)
|
||||
- Heading hierarchy constraints
|
||||
- Content density requirements (minimum paragraphs, code examples)
|
||||
- Formatting conventions (bold commands, italic arguments)
|
||||
|
||||
### 2. Self-Validating System
|
||||
|
||||
The schema validation manual validates against the manpage schema, proving:
|
||||
|
||||
- The schema is practical and usable
|
||||
- The manual follows manpage conventions
|
||||
- Schema validation works as documented
|
||||
- The system is reliable enough to document itself
|
||||
|
||||
### 3. Structural vs Semantic Validation
|
||||
|
||||
The schema validates **structure**, not **content**:
|
||||
|
||||
- ✅ Validates: Correct number of sections, heading levels, code examples present
|
||||
- ❌ Does not validate: Grammar, code correctness, factual accuracy, logical flow
|
||||
|
||||
This distinction is crucial for understanding what schemas can and cannot do.
|
||||
|
||||
### 4. Reusable Patterns
|
||||
|
||||
The manpage schema is a reusable pattern that can:
|
||||
|
||||
- Validate any Unix-style manual page
|
||||
- Enforce documentation consistency across a project
|
||||
- Generate templates for new documentation
|
||||
- Integrate into CI/CD pipelines for quality checks
|
||||
|
||||
### 5. Custom Schema Extensions
|
||||
|
||||
The schema demonstrates MarkiTect's custom extensions:
|
||||
|
||||
```json
|
||||
"x-markitect-required-sections": [
|
||||
"SYNOPSIS",
|
||||
"DESCRIPTION"
|
||||
],
|
||||
"x-markitect-recommended-sections": [
|
||||
"OPTIONS",
|
||||
"EXAMPLES",
|
||||
"SEE ALSO"
|
||||
],
|
||||
"x-markitect-conventions": {
|
||||
"heading_case": "UPPERCASE for H2 sections",
|
||||
"command_format": "Bold with **command**",
|
||||
"argument_format": "Italic with *ARG*"
|
||||
}
|
||||
```
|
||||
|
||||
These extensions provide metadata about schema intent and conventions beyond structural validation.
|
||||
|
||||
## Validation Workflow Demonstrated
|
||||
|
||||
This example shows the complete schema validation workflow:
|
||||
|
||||
### Step 1: Schema Creation
|
||||
- Analyze existing manpages (markitect.1.md, issue.1.md)
|
||||
- Identify common structural patterns
|
||||
- Generate base schema from example document
|
||||
- Refine schema to be flexible yet meaningful
|
||||
|
||||
### Step 2: Schema Refinement
|
||||
- Adjust minItems/maxItems for appropriate ranges
|
||||
- Add custom MarkiTect extensions
|
||||
- Include heading patterns and conventions
|
||||
- Balance strictness with flexibility
|
||||
|
||||
### Step 3: Document Creation
|
||||
- Write document following schema structure
|
||||
- Use template generated from schema as starting point
|
||||
- Ensure all required sections present
|
||||
- Include appropriate code examples and formatting
|
||||
|
||||
### Step 4: Validation
|
||||
- Validate document against schema
|
||||
- Review validation errors if any
|
||||
- Fix structural issues
|
||||
- Re-validate until passing
|
||||
|
||||
### Step 5: Iteration
|
||||
- Refine schema based on validation experience
|
||||
- Adjust constraints for real-world use cases
|
||||
- Document lessons learned
|
||||
- Share schema for reuse
|
||||
|
||||
## Integration Examples
|
||||
|
||||
### CI/CD Integration
|
||||
|
||||
Add to `.github/workflows/docs.yml` or similar:
|
||||
|
||||
```yaml
|
||||
- name: Validate Manpages
|
||||
run: |
|
||||
for manpage in docs/manuals/*.md; do
|
||||
markitect validate "$manpage" \
|
||||
--schema manpage-schema-v1.0.md \
|
||||
|| exit 1
|
||||
done
|
||||
```
|
||||
|
||||
### Pre-commit Hook
|
||||
|
||||
Add to `.git/hooks/pre-commit`:
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
changed_manpages=$(git diff --cached --name-only --diff-filter=ACM | grep 'docs/manuals/.*\.md$')
|
||||
|
||||
for manpage in $changed_manpages; do
|
||||
markitect validate "$manpage" \
|
||||
--schema manpage-schema-v1.0.md \
|
||||
--quiet || {
|
||||
echo "Manpage validation failed: $manpage"
|
||||
markitect validate "$manpage" \
|
||||
--schema manpage-schema-v1.0.md \
|
||||
--detailed-errors
|
||||
exit 1
|
||||
}
|
||||
done
|
||||
```
|
||||
|
||||
### Makefile Integration
|
||||
|
||||
Add to project `Makefile`:
|
||||
|
||||
```makefile
|
||||
.PHONY: validate-manpages
|
||||
validate-manpages:
|
||||
@echo "Validating manual pages..."
|
||||
@for manpage in docs/manuals/*.md; do \
|
||||
markitect validate "$$manpage" \
|
||||
--schema manpage-schema-v1.0.md \
|
||||
|| exit 1; \
|
||||
done
|
||||
@echo "✅ All manpages valid"
|
||||
|
||||
.PHONY: docs
|
||||
docs: validate-manpages
|
||||
# Continue with doc generation...
|
||||
```
|
||||
|
||||
## Key Lessons from This Example
|
||||
|
||||
### 1. Start with Real Documents
|
||||
|
||||
The manpage schema was created by analyzing existing manpages (markitect.1.md, issue.1.md), not designed in isolation. This ensures the schema reflects real-world usage.
|
||||
|
||||
### 2. Use Ranges, Not Exact Counts
|
||||
|
||||
The schema uses ranges like `5-500 paragraphs` instead of exact counts. This provides flexibility while still enforcing quality standards.
|
||||
|
||||
### 3. Required vs Recommended
|
||||
|
||||
The schema distinguishes between required sections (SYNOPSIS, DESCRIPTION) and recommended sections (EXAMPLES, SEE ALSO), allowing flexibility where appropriate.
|
||||
|
||||
### 4. Validate Structure, Not Semantics
|
||||
|
||||
Schemas validate document structure, not content quality. Grammar checking, code correctness, and factual accuracy require other tools.
|
||||
|
||||
### 5. Progressive Refinement
|
||||
|
||||
Schemas should evolve based on validation experience. Start loose, tighten based on actual needs, never over-specify.
|
||||
|
||||
### 6. Documentation is Essential
|
||||
|
||||
The schema includes extensive metadata about conventions and intent through custom extensions, making it self-documenting.
|
||||
|
||||
## Extending This Example
|
||||
|
||||
### Create Schema Variants
|
||||
|
||||
Create specialized schemas for different manpage types:
|
||||
|
||||
```bash
|
||||
# For command manpages (section 1)
|
||||
cp markitect/schemas/manpage-schema-v1.0.md command-manpage-schema-v1.0.md
|
||||
# Edit to require COMMANDS section
|
||||
markitect schema-validate ./command-manpage-schema-v1.0.md
|
||||
markitect schema-ingest ./command-manpage-schema-v1.0.md
|
||||
|
||||
# For format manpages (section 5)
|
||||
cp markitect/schemas/manpage-schema-v1.0.md format-manpage-schema-v1.0.md
|
||||
# Edit to require FORMAT section
|
||||
|
||||
# For convention manpages (section 7)
|
||||
cp markitect/schemas/manpage-schema-v1.0.md convention-manpage-schema-v1.0.md
|
||||
# Edit to be more flexible
|
||||
```
|
||||
|
||||
### Validate Your Own Documentation
|
||||
|
||||
Apply the manpage schema to your project:
|
||||
|
||||
```bash
|
||||
# Validate README (if it follows manpage structure)
|
||||
markitect validate README.md \
|
||||
--schema manpage-schema-v1.0.md
|
||||
|
||||
# May need adjustments for non-manpage docs
|
||||
```
|
||||
|
||||
### Generate Schema Family
|
||||
|
||||
Create schemas for related document types:
|
||||
|
||||
- API documentation schema
|
||||
- Tutorial schema
|
||||
- RFC/specification schema
|
||||
- Architecture decision record (ADR) schema
|
||||
|
||||
Each can follow similar validation principles while enforcing type-specific structure.
|
||||
|
||||
## Further Reading
|
||||
|
||||
- **markdown-schema-validation.1.md** - Complete reference for schema validation
|
||||
- **../../docs/manuals/markitect.1.md** - MarkiTect command reference
|
||||
- **JSON Schema Specification** - https://json-schema.org/
|
||||
- **Unix Manual Page Conventions** - `man 7 man-pages` on Unix systems
|
||||
|
||||
## Validation Results
|
||||
|
||||
This example has been validated to confirm:
|
||||
|
||||
✅ Manual validates against manpage schema
|
||||
✅ Schema is well-formed JSON Schema draft-07
|
||||
✅ All required sections present in manual
|
||||
✅ Heading hierarchy follows Unix conventions
|
||||
✅ Code examples demonstrate actual usage
|
||||
✅ Structure matches defined constraints
|
||||
|
||||
## License
|
||||
|
||||
Part of the MarkiTect project. Licensed under MIT License.
|
||||
|
||||
---
|
||||
|
||||
**Note**: This example represents a complete, production-ready use case of MarkiTect's schema validation system. The files can be used as-is or adapted for your own documentation requirements.
|
||||
230
examples/manpages/api-documentation-schema.json
Normal file
230
examples/manpages/api-documentation-schema.json
Normal file
@@ -0,0 +1,230 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"title": "API Endpoint Documentation Schema",
|
||||
"description": "Schema for API endpoint documentation with classification and content control",
|
||||
"x-markitect-sections": {
|
||||
"ENDPOINT": {
|
||||
"classification": "required",
|
||||
"heading_level": 2,
|
||||
"position": "after_title",
|
||||
"content_instruction": "HTTP method and endpoint path (e.g., GET /api/v1/users)",
|
||||
"min_paragraphs": 1,
|
||||
"max_paragraphs": 3,
|
||||
"error_message": "ENDPOINT section must specify the HTTP method and path"
|
||||
},
|
||||
"DESCRIPTION": {
|
||||
"classification": "required",
|
||||
"heading_level": 2,
|
||||
"content_instruction": "What this endpoint does and when to use it",
|
||||
"min_paragraphs": 2,
|
||||
"error_message": "DESCRIPTION is required to explain endpoint functionality"
|
||||
},
|
||||
"AUTHENTICATION": {
|
||||
"classification": "required",
|
||||
"heading_level": 2,
|
||||
"content_instruction": "Authentication requirements (API key, OAuth, etc.)",
|
||||
"min_paragraphs": 1,
|
||||
"error_message": "AUTHENTICATION requirements must be documented"
|
||||
},
|
||||
"REQUEST PARAMETERS": {
|
||||
"classification": "recommended",
|
||||
"heading_level": 2,
|
||||
"content_instruction": "List all request parameters with types and descriptions",
|
||||
"alternatives": ["PARAMETERS", "REQUEST", "INPUT"],
|
||||
"warning_if_missing": "Documenting request parameters helps API consumers use the endpoint correctly"
|
||||
},
|
||||
"RESPONSE": {
|
||||
"classification": "recommended",
|
||||
"heading_level": 2,
|
||||
"content_instruction": "Response format, status codes, and example responses",
|
||||
"min_code_blocks": 1,
|
||||
"warning_if_missing": "Response documentation with examples improves API usability"
|
||||
},
|
||||
"EXAMPLES": {
|
||||
"classification": "recommended",
|
||||
"heading_level": 2,
|
||||
"content_instruction": "Complete request/response examples",
|
||||
"min_code_blocks": 2,
|
||||
"warning_if_missing": "Examples make API documentation significantly more useful"
|
||||
},
|
||||
"ERROR CODES": {
|
||||
"classification": "recommended",
|
||||
"heading_level": 2,
|
||||
"content_instruction": "Possible error responses and how to handle them",
|
||||
"alternatives": ["ERRORS", "ERROR HANDLING"],
|
||||
"warning_if_missing": "Error documentation helps developers handle failures gracefully"
|
||||
},
|
||||
"RATE LIMITING": {
|
||||
"classification": "optional",
|
||||
"heading_level": 2,
|
||||
"content_instruction": "Rate limit information for this endpoint"
|
||||
},
|
||||
"CHANGELOG": {
|
||||
"classification": "optional",
|
||||
"heading_level": 2,
|
||||
"content_instruction": "Version history and changes to this endpoint"
|
||||
},
|
||||
"SEE ALSO": {
|
||||
"classification": "optional",
|
||||
"heading_level": 2,
|
||||
"content_instruction": "Related endpoints and documentation"
|
||||
},
|
||||
"IMPLEMENTATION NOTES": {
|
||||
"classification": "discouraged",
|
||||
"heading_level": 2,
|
||||
"warning_if_missing": "Implementation details should be in developer documentation, not API docs"
|
||||
},
|
||||
"INTERNAL API": {
|
||||
"classification": "improper",
|
||||
"heading_level": 2,
|
||||
"error_message": "Internal API endpoints must not be in public documentation"
|
||||
},
|
||||
"EXPERIMENTAL": {
|
||||
"classification": "improper",
|
||||
"heading_level": 2,
|
||||
"error_message": "Experimental features must not be in stable API documentation"
|
||||
}
|
||||
},
|
||||
"x-markitect-content-control": {
|
||||
"endpoint": {
|
||||
"required_patterns": [
|
||||
"\\*\\*[A-Z]+\\*\\*",
|
||||
"`/api/",
|
||||
"\\*\\*[A-Z]+\\*\\*\\s+`/[^`]+`"
|
||||
],
|
||||
"content_quality": {
|
||||
"min_words": 5,
|
||||
"max_words": 50,
|
||||
"readability_target": "technical"
|
||||
},
|
||||
"content_instructions": [
|
||||
"Format: **METHOD** `endpoint_path`",
|
||||
"Example: **GET** `/api/v1/users/{id}`",
|
||||
"Use bold for HTTP method",
|
||||
"Use code formatting for path",
|
||||
"Include path parameters in curly braces"
|
||||
]
|
||||
},
|
||||
"description": {
|
||||
"discouraged_patterns": [
|
||||
"TODO",
|
||||
"FIXME",
|
||||
"TBD",
|
||||
"Coming soon"
|
||||
],
|
||||
"forbidden_patterns": [
|
||||
"password",
|
||||
"secret",
|
||||
"api[_-]?key\\s*=",
|
||||
"token\\s*="
|
||||
],
|
||||
"content_quality": {
|
||||
"min_words": 30,
|
||||
"max_words": 500,
|
||||
"readability_target": "technical",
|
||||
"min_sentences": 2
|
||||
},
|
||||
"content_instructions": [
|
||||
"Explain what the endpoint does",
|
||||
"Describe the main use case",
|
||||
"Mention any prerequisites",
|
||||
"Note any side effects",
|
||||
"Keep concise but complete"
|
||||
]
|
||||
},
|
||||
"request_parameters": {
|
||||
"required_patterns": [
|
||||
"\\*\\*[a-z_]+\\*\\*",
|
||||
"\\*[A-Za-z]+\\*"
|
||||
],
|
||||
"content_instructions": [
|
||||
"Use bold for parameter names",
|
||||
"Use italic for parameter types",
|
||||
"Include: name, type, required/optional, description",
|
||||
"Use definition list format",
|
||||
"Specify default values where applicable"
|
||||
]
|
||||
},
|
||||
"response": {
|
||||
"required_patterns": [
|
||||
"```json",
|
||||
"200",
|
||||
"\\{[^}]*\\}"
|
||||
],
|
||||
"content_quality": {
|
||||
"min_words": 50,
|
||||
"max_words": 500,
|
||||
"readability_target": "technical"
|
||||
},
|
||||
"content_instructions": [
|
||||
"Show example JSON response",
|
||||
"Document all status codes",
|
||||
"Explain response fields",
|
||||
"Include success and error examples",
|
||||
"Use proper JSON formatting in code blocks"
|
||||
]
|
||||
},
|
||||
"examples": {
|
||||
"required_patterns": [
|
||||
"```bash",
|
||||
"curl",
|
||||
"```json"
|
||||
],
|
||||
"content_quality": {
|
||||
"min_words": 100,
|
||||
"max_words": 1000,
|
||||
"readability_target": "general"
|
||||
},
|
||||
"content_instructions": [
|
||||
"Provide complete curl examples",
|
||||
"Show request headers",
|
||||
"Include example responses",
|
||||
"Add explanatory comments",
|
||||
"Cover common scenarios"
|
||||
],
|
||||
"link_validation": {
|
||||
"check_internal": true,
|
||||
"check_external": true,
|
||||
"allow_fragments": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"headings": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"level_1": {
|
||||
"type": "array",
|
||||
"minItems": 1,
|
||||
"maxItems": 1
|
||||
},
|
||||
"level_2": {
|
||||
"type": "array",
|
||||
"minItems": 3,
|
||||
"maxItems": 15
|
||||
},
|
||||
"level_3": {
|
||||
"type": "array",
|
||||
"minItems": 0,
|
||||
"maxItems": 30
|
||||
}
|
||||
}
|
||||
},
|
||||
"paragraphs": {
|
||||
"type": "array",
|
||||
"minItems": 8,
|
||||
"maxItems": 200
|
||||
},
|
||||
"code_blocks": {
|
||||
"type": "array",
|
||||
"minItems": 3,
|
||||
"maxItems": 30
|
||||
},
|
||||
"emphasis": {
|
||||
"type": "array",
|
||||
"minItems": 15,
|
||||
"maxItems": 200
|
||||
}
|
||||
}
|
||||
}
|
||||
229
examples/manpages/enhanced-manpage-schema.json
Normal file
229
examples/manpages/enhanced-manpage-schema.json
Normal file
@@ -0,0 +1,229 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"title": "Enhanced Markdown Manpage Schema with Classifications",
|
||||
"description": "JSON schema for Unix-style manual pages with section classification and content control",
|
||||
"x-markitect-sections": {
|
||||
"SYNOPSIS": {
|
||||
"classification": "required",
|
||||
"heading_level": 2,
|
||||
"position": "after_title",
|
||||
"content_instruction": "Brief command syntax showing all options and arguments in standard format",
|
||||
"min_paragraphs": 1,
|
||||
"max_paragraphs": 5,
|
||||
"min_code_blocks": 0,
|
||||
"max_code_blocks": 3,
|
||||
"error_message": "SYNOPSIS section is mandatory for all manpages per Unix conventions"
|
||||
},
|
||||
"DESCRIPTION": {
|
||||
"classification": "required",
|
||||
"heading_level": 2,
|
||||
"content_instruction": "Detailed explanation of what the command does, its purpose, and main functionality",
|
||||
"min_paragraphs": 2,
|
||||
"max_paragraphs": 50,
|
||||
"error_message": "DESCRIPTION section is mandatory for all manpages"
|
||||
},
|
||||
"EXAMPLES": {
|
||||
"classification": "recommended",
|
||||
"heading_level": 2,
|
||||
"content_instruction": "Practical usage examples with explanations demonstrating common use cases",
|
||||
"min_code_blocks": 3,
|
||||
"max_code_blocks": 20,
|
||||
"warning_if_missing": "Examples greatly improve manpage usability - highly recommended"
|
||||
},
|
||||
"SEE ALSO": {
|
||||
"classification": "recommended",
|
||||
"heading_level": 2,
|
||||
"content_instruction": "Related commands, configuration files, and documentation references",
|
||||
"min_paragraphs": 1,
|
||||
"warning_if_missing": "Cross-references help users discover related functionality"
|
||||
},
|
||||
"OPTIONS": {
|
||||
"classification": "recommended",
|
||||
"heading_level": 2,
|
||||
"content_instruction": "Detailed option descriptions with all flags and their behaviors",
|
||||
"alternatives": ["GLOBAL OPTIONS", "COMMAND OPTIONS", "FLAGS"],
|
||||
"warning_if_missing": "Documenting command options helps users understand available functionality"
|
||||
},
|
||||
"BUGS": {
|
||||
"classification": "optional",
|
||||
"heading_level": 2,
|
||||
"content_instruction": "Known issues, limitations, and bug reporting information"
|
||||
},
|
||||
"AUTHORS": {
|
||||
"classification": "optional",
|
||||
"heading_level": 2,
|
||||
"content_instruction": "List of contributors and maintainers"
|
||||
},
|
||||
"COPYRIGHT": {
|
||||
"classification": "optional",
|
||||
"heading_level": 2,
|
||||
"content_instruction": "Copyright statement and license information"
|
||||
},
|
||||
"HISTORY": {
|
||||
"classification": "optional",
|
||||
"heading_level": 2,
|
||||
"content_instruction": "Historical information about command development"
|
||||
},
|
||||
"DEPRECATED": {
|
||||
"classification": "discouraged",
|
||||
"heading_level": 2,
|
||||
"warning_if_missing": "Consider moving deprecated content to historical documentation or HISTORY section"
|
||||
},
|
||||
"OLD_SYNTAX": {
|
||||
"classification": "discouraged",
|
||||
"heading_level": 2,
|
||||
"warning_if_missing": "Old syntax should be documented in HISTORY or removed entirely"
|
||||
},
|
||||
"INTERNAL_NOTES": {
|
||||
"classification": "improper",
|
||||
"heading_level": 2,
|
||||
"error_message": "Internal notes must not appear in published manpages - move to developer documentation"
|
||||
},
|
||||
"TODO": {
|
||||
"classification": "improper",
|
||||
"heading_level": 2,
|
||||
"error_message": "TODO sections are for development only - remove before publication"
|
||||
},
|
||||
"DRAFT": {
|
||||
"classification": "improper",
|
||||
"heading_level": 2,
|
||||
"error_message": "DRAFT markers must be removed before publication"
|
||||
}
|
||||
},
|
||||
"x-markitect-content-control": {
|
||||
"synopsis": {
|
||||
"required_patterns": [
|
||||
"\\*\\*[a-z][a-z0-9-]*\\*\\*",
|
||||
"\\[.*\\]"
|
||||
],
|
||||
"discouraged_patterns": [
|
||||
"TODO",
|
||||
"FIXME",
|
||||
"TBD"
|
||||
],
|
||||
"content_quality": {
|
||||
"min_words": 5,
|
||||
"max_words": 150,
|
||||
"readability_target": "technical"
|
||||
},
|
||||
"content_instructions": [
|
||||
"Show command name in bold (e.g., **command**)",
|
||||
"Use brackets [] for optional arguments",
|
||||
"Use italic *ARG* for required arguments",
|
||||
"Keep synopsis concise (1-5 lines maximum)",
|
||||
"Use ellipsis ... to indicate repeatable arguments"
|
||||
]
|
||||
},
|
||||
"description": {
|
||||
"discouraged_patterns": [
|
||||
"TODO",
|
||||
"FIXME",
|
||||
"\\bWIP\\b",
|
||||
"\\bXXX\\b"
|
||||
],
|
||||
"forbidden_patterns": [
|
||||
"password\\s*=\\s*[\"'].*[\"']",
|
||||
"api[_-]?key\\s*=\\s*[\"'].*[\"']",
|
||||
"secret\\s*=\\s*[\"'].*[\"']"
|
||||
],
|
||||
"content_quality": {
|
||||
"min_words": 50,
|
||||
"max_words": 1000,
|
||||
"readability_target": "technical",
|
||||
"min_sentences": 3
|
||||
},
|
||||
"content_instructions": [
|
||||
"Start with what the command does",
|
||||
"Explain why users would use it",
|
||||
"Describe main functionality and features",
|
||||
"Mention any prerequisites or requirements",
|
||||
"Keep technical but accessible"
|
||||
],
|
||||
"link_validation": {
|
||||
"check_internal": true,
|
||||
"check_external": false,
|
||||
"allow_fragments": true
|
||||
}
|
||||
},
|
||||
"examples": {
|
||||
"required_patterns": [
|
||||
"```",
|
||||
"#"
|
||||
],
|
||||
"content_quality": {
|
||||
"min_words": 100,
|
||||
"max_words": 2000,
|
||||
"readability_target": "general"
|
||||
},
|
||||
"content_instructions": [
|
||||
"Use bash code blocks for command examples",
|
||||
"Include comments explaining what each example does",
|
||||
"Start with simple examples, progress to complex",
|
||||
"Show actual output when helpful",
|
||||
"Cover common use cases first"
|
||||
]
|
||||
}
|
||||
},
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"headings": {
|
||||
"type": "object",
|
||||
"description": "Document heading structure",
|
||||
"properties": {
|
||||
"level_1": {
|
||||
"type": "array",
|
||||
"description": "Title heading in format: command(section) - description",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"content": {
|
||||
"type": "string",
|
||||
"pattern": "^[a-z0-9-]+\\([0-9]\\) - .+"
|
||||
}
|
||||
}
|
||||
},
|
||||
"minItems": 1,
|
||||
"maxItems": 1
|
||||
},
|
||||
"level_2": {
|
||||
"type": "array",
|
||||
"description": "Main section headings",
|
||||
"minItems": 3,
|
||||
"maxItems": 30
|
||||
},
|
||||
"level_3": {
|
||||
"type": "array",
|
||||
"description": "Subsection headings",
|
||||
"minItems": 0,
|
||||
"maxItems": 50
|
||||
}
|
||||
},
|
||||
"required": ["level_1", "level_2"]
|
||||
},
|
||||
"paragraphs": {
|
||||
"type": "array",
|
||||
"description": "Text paragraphs",
|
||||
"minItems": 10,
|
||||
"maxItems": 500
|
||||
},
|
||||
"code_blocks": {
|
||||
"type": "array",
|
||||
"description": "Code examples",
|
||||
"minItems": 1,
|
||||
"maxItems": 50
|
||||
},
|
||||
"lists": {
|
||||
"type": "array",
|
||||
"description": "Lists for options and structured information",
|
||||
"minItems": 0,
|
||||
"maxItems": 100
|
||||
},
|
||||
"emphasis": {
|
||||
"type": "array",
|
||||
"description": "Bold and italic text for commands and arguments",
|
||||
"minItems": 20,
|
||||
"maxItems": 500
|
||||
}
|
||||
},
|
||||
"required": ["headings", "paragraphs", "code_blocks", "emphasis"]
|
||||
}
|
||||
246
examples/manpages/markdown-manpage-schema.json
Normal file
246
examples/manpages/markdown-manpage-schema.json
Normal file
@@ -0,0 +1,246 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"type": "object",
|
||||
"title": "Markdown Manpage Schema",
|
||||
"description": "JSON schema defining the structure of Unix-style manual pages written in Markdown. Compatible with man(1) section format and conventions.",
|
||||
"x-markitect-sections": {
|
||||
"SYNOPSIS": {
|
||||
"classification": "required",
|
||||
"heading_level": 2,
|
||||
"position": "after_title",
|
||||
"content_instruction": "Brief command syntax showing options and arguments in standard Unix format",
|
||||
"min_paragraphs": 1,
|
||||
"max_paragraphs": 5,
|
||||
"error_message": "SYNOPSIS section is mandatory for all Unix manual pages"
|
||||
},
|
||||
"DESCRIPTION": {
|
||||
"classification": "required",
|
||||
"heading_level": 2,
|
||||
"content_instruction": "Detailed explanation of the command's purpose and functionality",
|
||||
"min_paragraphs": 2,
|
||||
"error_message": "DESCRIPTION section is mandatory for all Unix manual pages"
|
||||
},
|
||||
"OPTIONS": {
|
||||
"classification": "recommended",
|
||||
"heading_level": 2,
|
||||
"content_instruction": "Command-line options and flags with descriptions",
|
||||
"alternatives": ["GLOBAL OPTIONS", "COMMAND OPTIONS", "FLAGS"],
|
||||
"warning_if_missing": "Documenting command options improves usability"
|
||||
},
|
||||
"EXAMPLES": {
|
||||
"classification": "recommended",
|
||||
"heading_level": 2,
|
||||
"content_instruction": "Practical usage examples demonstrating common use cases",
|
||||
"min_code_blocks": 2,
|
||||
"warning_if_missing": "Examples significantly improve manpage usability and comprehension"
|
||||
},
|
||||
"SEE ALSO": {
|
||||
"classification": "recommended",
|
||||
"heading_level": 2,
|
||||
"content_instruction": "Related commands, configuration files, and documentation references",
|
||||
"warning_if_missing": "Cross-references help users discover related functionality"
|
||||
},
|
||||
"COPYRIGHT": {
|
||||
"classification": "recommended",
|
||||
"heading_level": 2,
|
||||
"content_instruction": "Copyright statement and license information",
|
||||
"warning_if_missing": "License information should be documented for clarity"
|
||||
},
|
||||
"COMMANDS": {
|
||||
"classification": "optional",
|
||||
"heading_level": 2,
|
||||
"content_instruction": "Subcommands and their brief descriptions"
|
||||
},
|
||||
"CONFIGURATION": {
|
||||
"classification": "optional",
|
||||
"heading_level": 2,
|
||||
"content_instruction": "Configuration file format and options"
|
||||
},
|
||||
"FILES": {
|
||||
"classification": "optional",
|
||||
"heading_level": 2,
|
||||
"content_instruction": "Important files used by the command with their purposes"
|
||||
},
|
||||
"EXIT STATUS": {
|
||||
"classification": "optional",
|
||||
"heading_level": 2,
|
||||
"content_instruction": "Exit codes and their meanings"
|
||||
},
|
||||
"ENVIRONMENT": {
|
||||
"classification": "optional",
|
||||
"heading_level": 2,
|
||||
"content_instruction": "Environment variables used or set by the command"
|
||||
},
|
||||
"BUGS": {
|
||||
"classification": "optional",
|
||||
"heading_level": 2,
|
||||
"content_instruction": "Known issues and bug reporting instructions"
|
||||
},
|
||||
"AUTHORS": {
|
||||
"classification": "optional",
|
||||
"heading_level": 2,
|
||||
"content_instruction": "List of contributors and maintainers"
|
||||
}
|
||||
},
|
||||
"x-markitect-content-control": {
|
||||
"synopsis": {
|
||||
"required_patterns": [
|
||||
"\\*\\*[a-z][a-z0-9-]*\\*\\*",
|
||||
"\\[.*\\]"
|
||||
],
|
||||
"discouraged_patterns": [
|
||||
"TODO",
|
||||
"FIXME"
|
||||
],
|
||||
"content_quality": {
|
||||
"min_words": 5,
|
||||
"max_words": 150,
|
||||
"readability_target": "technical"
|
||||
},
|
||||
"content_instructions": [
|
||||
"Show command name in bold: **command**",
|
||||
"Use brackets [] for optional arguments",
|
||||
"Use italic *ARG* for required arguments",
|
||||
"Keep synopsis concise (1-5 lines)",
|
||||
"Follow man(1) synopsis conventions"
|
||||
]
|
||||
},
|
||||
"description": {
|
||||
"discouraged_patterns": [
|
||||
"TODO",
|
||||
"FIXME",
|
||||
"\\bWIP\\b",
|
||||
"TBD"
|
||||
],
|
||||
"forbidden_patterns": [
|
||||
"password\\s*=\\s*[\"'].*[\"']",
|
||||
"api[_-]?key\\s*=\\s*[\"'].*[\"']"
|
||||
],
|
||||
"content_quality": {
|
||||
"min_words": 50,
|
||||
"max_words": 1000,
|
||||
"readability_target": "technical",
|
||||
"min_sentences": 3
|
||||
},
|
||||
"content_instructions": [
|
||||
"Explain what the command does",
|
||||
"Describe the primary purpose",
|
||||
"Mention key features and capabilities",
|
||||
"Note any prerequisites or dependencies",
|
||||
"Keep language clear and technical"
|
||||
]
|
||||
},
|
||||
"examples": {
|
||||
"required_patterns": [
|
||||
"```",
|
||||
"#"
|
||||
],
|
||||
"content_quality": {
|
||||
"min_words": 50,
|
||||
"max_words": 2000,
|
||||
"readability_target": "general"
|
||||
},
|
||||
"content_instructions": [
|
||||
"Use bash code blocks with syntax highlighting",
|
||||
"Include comments explaining each example",
|
||||
"Start with simple examples, progress to complex",
|
||||
"Show actual output when helpful",
|
||||
"Cover the most common use cases"
|
||||
]
|
||||
}
|
||||
},
|
||||
"properties": {
|
||||
"headings": {
|
||||
"type": "object",
|
||||
"description": "Document heading structure following Unix manpage conventions",
|
||||
"properties": {
|
||||
"level_1": {
|
||||
"type": "array",
|
||||
"description": "Title heading: command(section) - brief description",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"content": {
|
||||
"type": "string",
|
||||
"pattern": "^[a-z0-9-]+\\([0-9]\\) - .+",
|
||||
"description": "Must follow format: command(section) - description"
|
||||
},
|
||||
"level": {
|
||||
"type": "integer",
|
||||
"const": 1
|
||||
}
|
||||
},
|
||||
"required": ["content", "level"]
|
||||
},
|
||||
"minItems": 1,
|
||||
"maxItems": 1
|
||||
},
|
||||
"level_2": {
|
||||
"type": "array",
|
||||
"description": "Main section headings (SYNOPSIS, DESCRIPTION, etc.)",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"content": {
|
||||
"type": "string",
|
||||
"description": "Section name in UPPERCASE"
|
||||
},
|
||||
"level": {
|
||||
"type": "integer",
|
||||
"const": 2
|
||||
}
|
||||
},
|
||||
"required": ["content", "level"]
|
||||
},
|
||||
"minItems": 3,
|
||||
"maxItems": 30
|
||||
},
|
||||
"level_3": {
|
||||
"type": "array",
|
||||
"description": "Subsection headings (optional, for grouping commands or options)",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"content": {
|
||||
"type": "string"
|
||||
},
|
||||
"level": {
|
||||
"type": "integer",
|
||||
"const": 3
|
||||
}
|
||||
},
|
||||
"required": ["content", "level"]
|
||||
},
|
||||
"minItems": 0,
|
||||
"maxItems": 50
|
||||
}
|
||||
},
|
||||
"required": ["level_1", "level_2"]
|
||||
},
|
||||
"paragraphs": {
|
||||
"type": "array",
|
||||
"description": "Text paragraphs containing descriptions and explanations",
|
||||
"minItems": 5,
|
||||
"maxItems": 500
|
||||
},
|
||||
"lists": {
|
||||
"type": "array",
|
||||
"description": "Lists for options, examples, or structured information",
|
||||
"minItems": 0,
|
||||
"maxItems": 100
|
||||
},
|
||||
"code_blocks": {
|
||||
"type": "array",
|
||||
"description": "Code examples and command demonstrations",
|
||||
"minItems": 1,
|
||||
"maxItems": 50
|
||||
},
|
||||
"emphasis": {
|
||||
"type": "array",
|
||||
"description": "Bold and italic emphasis for commands, options, and arguments",
|
||||
"minItems": 10,
|
||||
"maxItems": 500
|
||||
}
|
||||
},
|
||||
"required": ["headings", "paragraphs", "code_blocks", "emphasis"]
|
||||
}
|
||||
901
examples/manpages/markdown-schema-validation.1.md
Normal file
901
examples/manpages/markdown-schema-validation.1.md
Normal file
@@ -0,0 +1,901 @@
|
||||
# markdown-schema-validation(7) - Structured Document Validation with JSON Schema
|
||||
|
||||
## SYNOPSIS
|
||||
|
||||
**markitect schema-generate** *SOURCE_FILE* [**--output** *SCHEMA_FILE*]
|
||||
|
||||
**markitect schema-ingest** *SCHEMA_FILE*
|
||||
|
||||
**markitect validate** *DOCUMENT* *SCHEMA*
|
||||
|
||||
**markitect generate-stub** *SCHEMA* [**--output** *FILE*]
|
||||
|
||||
## DESCRIPTION
|
||||
|
||||
Markdown Schema Validation is MarkiTect's system for enforcing structural consistency in markdown documents. Unlike traditional markdown linters that check syntax, schema validation ensures documents conform to predefined structural patterns by validating their Abstract Syntax Tree (AST) representation against JSON Schema definitions.
|
||||
|
||||
This approach enables content management workflows where document structure is as important as content, making it ideal for technical documentation, business documents, and any scenario requiring consistent document templates.
|
||||
|
||||
### How Schema Validation Works
|
||||
|
||||
MarkiTect parses markdown files into an AST representation, then validates the AST structure against JSON schemas. The validation process checks:
|
||||
|
||||
- **Heading hierarchy** - Required heading levels and counts
|
||||
- **Content elements** - Minimum and maximum paragraph counts
|
||||
- **Structural patterns** - Presence of lists, code blocks, tables
|
||||
- **Section organization** - Required and optional document sections
|
||||
|
||||
Schemas validate structure, not semantics. A document can pass validation while containing incorrect content, as long as the structure matches the schema.
|
||||
|
||||
## OPTIONS
|
||||
|
||||
### Validation Options
|
||||
|
||||
**--schema** *PATH*, **-s** *PATH*
|
||||
: Path to JSON schema file for validation
|
||||
: Used with **validate** command to specify schema location
|
||||
|
||||
**--schema-json** *TEXT*
|
||||
: JSON schema provided as inline string
|
||||
: Alternative to --schema for programmatic use
|
||||
: Useful for testing or dynamic schema generation
|
||||
|
||||
**--detailed-errors**, **--errors**
|
||||
: Show detailed validation errors with line numbers
|
||||
: Provides specific locations and descriptions of failures
|
||||
: Essential for debugging complex schema validation issues
|
||||
|
||||
**--error-format** *FORMAT*
|
||||
: Format for error output: **text**, **json**, or **markdown**
|
||||
: Default: **text**
|
||||
: JSON format useful for CI/CD pipeline integration
|
||||
: Markdown format for inclusion in documentation
|
||||
|
||||
**--quiet**, **-q**
|
||||
: Only output validation result (true/false)
|
||||
: Suppresses all other output for scripting
|
||||
: Exit code indicates success (0) or failure (non-zero)
|
||||
|
||||
### Schema Generation Options
|
||||
|
||||
**--output** *PATH*, **-o** *PATH*
|
||||
: Output file path for generated schema or document
|
||||
: Used with **schema-generate** and **generate-stub** commands
|
||||
: If omitted, outputs to stdout
|
||||
|
||||
**--style** *STYLE*
|
||||
: Placeholder content style for **generate-stub** command
|
||||
: Options: **default**, **custom**, **detailed**
|
||||
: Affects the verbosity of generated stub content
|
||||
|
||||
**--title** *TEXT*
|
||||
: Custom document title for generated stubs
|
||||
: Overrides default title derived from schema
|
||||
: Useful for creating multiple documents from one schema
|
||||
|
||||
### Schema Management Options
|
||||
|
||||
**--schema-list**
|
||||
: List all available schemas in the library
|
||||
: Shows schema names and descriptions
|
||||
: Helps discover reusable schema patterns
|
||||
|
||||
**--schema-info** *SCHEMA_NAME*
|
||||
: Display detailed information about a specific schema
|
||||
: Shows schema structure, requirements, and metadata
|
||||
: Useful for understanding schema capabilities before use
|
||||
|
||||
**--schema-delete** *SCHEMA_NAME*
|
||||
: Remove a schema from the library
|
||||
: Requires confirmation unless **--confirm** flag is used
|
||||
: Irreversible operation - use with caution
|
||||
|
||||
**--confirm**
|
||||
: Skip confirmation prompts for destructive operations
|
||||
: Used with **schema-delete** and similar commands
|
||||
: Useful for automation scripts
|
||||
|
||||
### Phase 2 Schema Refinement Options
|
||||
|
||||
**--verbose**, **-v**
|
||||
: Show detailed analysis with current and suggested values
|
||||
: Used with **schema-analyze** command
|
||||
: Provides comprehensive rigidity assessment
|
||||
|
||||
**--dry-run**
|
||||
: Preview refinement changes without applying them
|
||||
: Used with **schema-refine** command
|
||||
: Allows review before modifying schemas
|
||||
|
||||
**--interactive**, **-i**
|
||||
: Prompt for each refinement interactively
|
||||
: Used with **schema-refine** command
|
||||
: Provides fine-grained control over applied fixes
|
||||
|
||||
**--loosen-counts**
|
||||
: Convert exact counts to flexible ranges (default: enabled)
|
||||
: Part of schema refinement process
|
||||
: Can be disabled with **--no-loosen-counts**
|
||||
|
||||
**--round-numbers**
|
||||
: Round overly specific numbers (default: enabled)
|
||||
: Improves schema reusability
|
||||
: Can be disabled with **--no-round-numbers**
|
||||
|
||||
**--migrate-deprecated**
|
||||
: Document deprecated extension usage
|
||||
: Helps identify schemas needing manual migration
|
||||
: Does not automatically migrate (too risky)
|
||||
|
||||
## SCHEMA STRUCTURE
|
||||
|
||||
### JSON Schema Format
|
||||
|
||||
MarkiTect schemas are standard JSON Schema (draft-07) documents with custom extensions for markdown-specific validation.
|
||||
|
||||
#### Standard Properties
|
||||
|
||||
**properties.headings**
|
||||
: Defines heading structure by level (level_1, level_2, level_3)
|
||||
: Each level specifies minItems, maxItems, and content patterns
|
||||
|
||||
**properties.paragraphs**
|
||||
: Array constraints for paragraph counts
|
||||
: Validates document length and content density
|
||||
|
||||
**properties.code_blocks**
|
||||
: Array constraints for code examples
|
||||
: Ensures technical documentation includes examples
|
||||
|
||||
**properties.lists**
|
||||
: Array constraints for list elements
|
||||
: Validates presence of structured information
|
||||
|
||||
**properties.emphasis**
|
||||
: Array constraints for bold and italic text
|
||||
: Ensures appropriate use of emphasis
|
||||
|
||||
#### MarkiTect Extensions
|
||||
|
||||
MarkiTect extends JSON Schema with custom properties prefixed with **x-markitect-**:
|
||||
|
||||
**x-markitect-sections**
|
||||
: Section classification and content control system
|
||||
: Defines sections with five classification levels:
|
||||
: - **required**: Must be present (validation fails if missing)
|
||||
: - **recommended**: Should be present (warning if missing)
|
||||
: - **optional**: May be present (no validation impact)
|
||||
: - **discouraged**: Should not be present (warning if present)
|
||||
: - **improper**: Must not be present (validation fails if present)
|
||||
: Each section can specify content instructions, constraints, and custom messages
|
||||
|
||||
**x-markitect-content-control**
|
||||
: Content validation rules for section content
|
||||
: Defines required/discouraged/forbidden patterns
|
||||
: Specifies content quality metrics (word count, readability)
|
||||
: Provides content instructions for authors
|
||||
|
||||
**x-markitect-outline-mode**
|
||||
: Boolean enabling outline-only validation
|
||||
: Focuses on heading structure without content validation
|
||||
|
||||
**x-markitect-heading-text-capture**
|
||||
: Boolean enabling exact heading text validation
|
||||
: Enforces specific section names
|
||||
|
||||
## COMMANDS
|
||||
|
||||
### Schema Generation
|
||||
|
||||
**markitect schema-generate** *SOURCE_FILE*
|
||||
: Analyzes markdown file AST and generates JSON schema
|
||||
: Schema describes actual structure found in source document
|
||||
|
||||
**--output** *SCHEMA_FILE*
|
||||
: Write schema to file instead of stdout
|
||||
: Default: outputs to terminal
|
||||
|
||||
**--max-depth** *N*
|
||||
: Limit heading analysis to depth N
|
||||
: Useful for outline-focused schemas
|
||||
|
||||
### Schema Management
|
||||
|
||||
**markitect schema-ingest** *SCHEMA_FILE*
|
||||
: Store schema in MarkiTect database
|
||||
: Registers schema for reuse with validation commands
|
||||
|
||||
**markitect schema-list**
|
||||
: Display all stored schemas
|
||||
: Shows schema names and metadata
|
||||
|
||||
**markitect schema-get** *SCHEMA_NAME*
|
||||
: Retrieve stored schema
|
||||
: Outputs JSON schema to stdout
|
||||
|
||||
**markitect schema-delete** *SCHEMA_NAME*
|
||||
: Remove schema from database
|
||||
: Permanently deletes schema definition
|
||||
|
||||
### Document Validation
|
||||
|
||||
**markitect validate** *DOCUMENT* *SCHEMA*
|
||||
: Validate markdown document against schema
|
||||
: Returns exit code 0 for valid, 4 for invalid
|
||||
|
||||
**--detailed-errors**
|
||||
: Show detailed validation error messages
|
||||
: Includes suggestions for fixing violations
|
||||
|
||||
**--quiet**
|
||||
: Suppress output, exit code only
|
||||
: Useful for scripting and automation
|
||||
|
||||
### Template Generation
|
||||
|
||||
**markitect generate-stub** *SCHEMA*
|
||||
: Generate markdown template from schema
|
||||
: Creates document outline following schema structure
|
||||
|
||||
**--output** *FILE*
|
||||
: Write template to file
|
||||
: Default: outputs to stdout
|
||||
|
||||
## WORKFLOW
|
||||
|
||||
### Schema-Driven Development Workflow
|
||||
|
||||
The typical workflow for schema-based document management:
|
||||
|
||||
**1. Generate Schema from Example**
|
||||
|
||||
Create or identify an exemplar document with the desired structure, then generate its schema:
|
||||
|
||||
```bash
|
||||
markitect schema-generate exemplar.md --output doc-schema.json
|
||||
```
|
||||
|
||||
**2. Refine Schema**
|
||||
|
||||
Edit the generated schema to adjust constraints:
|
||||
|
||||
- Change minItems/maxItems for flexibility
|
||||
- Add required-sections extensions
|
||||
- Adjust heading patterns
|
||||
- Add content instructions
|
||||
|
||||
**3. Store Schema**
|
||||
|
||||
Register schema for reuse:
|
||||
|
||||
```bash
|
||||
markitect schema-ingest doc-schema.json
|
||||
```
|
||||
|
||||
**4. Generate Templates**
|
||||
|
||||
Create document templates from schema:
|
||||
|
||||
```bash
|
||||
markitect generate-stub doc-schema.json --output template.md
|
||||
```
|
||||
|
||||
**5. Create Documents**
|
||||
|
||||
Write new documents using template as starting point, or use existing documents.
|
||||
|
||||
**6. Validate Documents**
|
||||
|
||||
Ensure documents conform to schema:
|
||||
|
||||
```bash
|
||||
markitect validate new-document.md doc-schema.json
|
||||
|
||||
markitect validate new-document.md doc-schema.json --detailed-errors
|
||||
```
|
||||
|
||||
**7. Iterate**
|
||||
|
||||
Fix validation errors and re-validate until document passes.
|
||||
|
||||
### Batch Validation Workflow
|
||||
|
||||
For managing multiple documents:
|
||||
|
||||
```bash
|
||||
for doc in docs/*.md; do
|
||||
markitect validate "$doc" doc-schema.json --quiet || echo "Failed: $doc"
|
||||
done
|
||||
```
|
||||
|
||||
## VALIDATION RULES
|
||||
|
||||
### Heading Validation
|
||||
|
||||
Schemas validate heading structure through the **headings** property:
|
||||
|
||||
**level_1** headings must appear exactly once (document title)
|
||||
|
||||
**level_2** headings represent major sections (minItems/maxItems set bounds)
|
||||
|
||||
**level_3** headings provide subsections (often optional with minItems: 0)
|
||||
|
||||
Heading content can be validated with **pattern** or **enum** constraints for exact section names.
|
||||
|
||||
### Content Element Validation
|
||||
|
||||
**Paragraphs** - Validates document has sufficient descriptive content
|
||||
|
||||
**Code blocks** - Ensures technical documents include examples
|
||||
|
||||
**Lists** - Validates structured information presence
|
||||
|
||||
**Emphasis** - Checks for appropriate use of bold/italic formatting
|
||||
|
||||
Constraints use **minItems** and **maxItems** to set acceptable ranges.
|
||||
|
||||
### Metadata Validation
|
||||
|
||||
The **metadata** property validates overall document characteristics:
|
||||
|
||||
**total_elements** - Total AST node count
|
||||
|
||||
**structure_types** - Array of AST node types present
|
||||
|
||||
Use **const** for exact matches or ranges for flexibility.
|
||||
|
||||
### Section Classification System
|
||||
|
||||
MarkiTect provides a five-level classification system for document sections through **x-markitect-sections**:
|
||||
|
||||
#### Required Sections
|
||||
|
||||
Sections marked as **required** must be present in the document. Validation fails with an error if missing.
|
||||
|
||||
```json
|
||||
"SYNOPSIS": {
|
||||
"classification": "required",
|
||||
"error_message": "SYNOPSIS section is mandatory for all manpages"
|
||||
}
|
||||
```
|
||||
|
||||
**Validation Behavior**:
|
||||
- Missing → ERROR → validation fails
|
||||
- Present → Continue validation
|
||||
|
||||
#### Recommended Sections
|
||||
|
||||
Sections marked as **recommended** should be present. A warning is generated if missing, but validation succeeds.
|
||||
|
||||
```json
|
||||
"EXAMPLES": {
|
||||
"classification": "recommended",
|
||||
"warning_if_missing": "Examples improve documentation usability"
|
||||
}
|
||||
```
|
||||
|
||||
**Validation Behavior**:
|
||||
- Missing → WARNING → validation succeeds with warnings
|
||||
- Present → Continue validation
|
||||
|
||||
#### Optional Sections
|
||||
|
||||
Sections marked as **optional** may or may not be present with no validation impact.
|
||||
|
||||
```json
|
||||
"BUGS": {
|
||||
"classification": "optional",
|
||||
"content_instruction": "Known issues and bug reporting"
|
||||
}
|
||||
```
|
||||
|
||||
**Validation Behavior**:
|
||||
- Missing → No impact
|
||||
- Present → Continue validation
|
||||
|
||||
#### Discouraged Sections
|
||||
|
||||
Sections marked as **discouraged** should not be present. A warning is generated if found, but validation succeeds.
|
||||
|
||||
```json
|
||||
"DEPRECATED": {
|
||||
"classification": "discouraged",
|
||||
"warning_if_missing": "Move deprecated content to HISTORY section"
|
||||
}
|
||||
```
|
||||
|
||||
**Validation Behavior**:
|
||||
- Missing → No impact
|
||||
- Present → WARNING → validation succeeds with warnings
|
||||
|
||||
#### Improper Sections
|
||||
|
||||
Sections marked as **improper** must not be present. Validation fails with an error if found.
|
||||
|
||||
```json
|
||||
"TODO": {
|
||||
"classification": "improper",
|
||||
"error_message": "TODO sections must be removed before publication"
|
||||
}
|
||||
```
|
||||
|
||||
**Validation Behavior**:
|
||||
- Missing → No impact
|
||||
- Present → ERROR → validation fails
|
||||
|
||||
### Content Control
|
||||
|
||||
The **x-markitect-content-control** extension enables content-level validation:
|
||||
|
||||
#### Pattern Validation
|
||||
|
||||
**required_patterns** - Array of regex patterns that must appear in content:
|
||||
```json
|
||||
"required_patterns": ["\\*\\*command\\*\\*", "\\[.*\\]"]
|
||||
```
|
||||
|
||||
**discouraged_patterns** - Patterns that should not appear (generates warnings):
|
||||
```json
|
||||
"discouraged_patterns": ["TODO", "FIXME", "\\bWIP\\b"]
|
||||
```
|
||||
|
||||
**forbidden_patterns** - Patterns that must not appear (validation fails):
|
||||
```json
|
||||
"forbidden_patterns": ["password\\s*=", "api[_-]?key\\s*="]
|
||||
```
|
||||
|
||||
#### Content Quality Metrics
|
||||
|
||||
Validate content length and readability:
|
||||
|
||||
```json
|
||||
"content_quality": {
|
||||
"min_words": 50,
|
||||
"max_words": 1000,
|
||||
"readability_target": "technical",
|
||||
"min_sentences": 3
|
||||
}
|
||||
```
|
||||
|
||||
**Readability Targets**:
|
||||
- **simple** - Elementary school level
|
||||
- **general** - General audience
|
||||
- **technical** - Technical audience (default for documentation)
|
||||
- **advanced** - Expert/academic level
|
||||
|
||||
#### Content Instructions
|
||||
|
||||
Provide guidance for content authors:
|
||||
|
||||
```json
|
||||
"content_instructions": [
|
||||
"Show command name in bold",
|
||||
"Use brackets [] for optional arguments",
|
||||
"Keep synopsis concise (1-5 lines)"
|
||||
]
|
||||
```
|
||||
|
||||
These instructions appear in validation reports and generated templates.
|
||||
|
||||
## ERROR HANDLING
|
||||
|
||||
### Common Validation Errors
|
||||
|
||||
**Missing Required Section**
|
||||
|
||||
```
|
||||
Error: Required section 'SYNOPSIS' not found
|
||||
Suggestion: Add H2 heading '## SYNOPSIS' near document start
|
||||
```
|
||||
|
||||
**Insufficient Content**
|
||||
|
||||
```
|
||||
Error: Too few paragraphs (found 3, minimum 5 required)
|
||||
Suggestion: Add descriptive content to meet minimum paragraph count
|
||||
```
|
||||
|
||||
**Heading Count Mismatch**
|
||||
|
||||
```
|
||||
Error: Too many H2 headings (found 15, maximum 13 allowed)
|
||||
Suggestion: Combine related sections or adjust schema maxItems
|
||||
```
|
||||
|
||||
**Structure Type Mismatch**
|
||||
|
||||
```
|
||||
Error: Expected structure types not found: code_blocks
|
||||
Suggestion: Add code examples using fenced code blocks
|
||||
```
|
||||
|
||||
### Using Detailed Error Mode
|
||||
|
||||
Enable detailed errors for actionable feedback:
|
||||
|
||||
```bash
|
||||
markitect validate document.md schema.json --detailed-errors
|
||||
```
|
||||
|
||||
Output includes:
|
||||
- Specific constraint violations
|
||||
- Location information when available
|
||||
- Suggestions for fixes
|
||||
- Schema path to failing constraint
|
||||
|
||||
## SCHEMA DESIGN
|
||||
|
||||
### Best Practices
|
||||
|
||||
**Start with Real Documents**
|
||||
|
||||
Generate schemas from actual documents rather than writing from scratch. Real documents provide realistic constraints.
|
||||
|
||||
**Use Ranges, Not Exact Counts**
|
||||
|
||||
Allow flexibility with minItems/maxItems ranges:
|
||||
|
||||
```json
|
||||
"paragraphs": {
|
||||
"minItems": 10,
|
||||
"maxItems": 100
|
||||
}
|
||||
```
|
||||
|
||||
Avoid exact counts (**const**) unless structure is truly rigid.
|
||||
|
||||
**Section Classification**
|
||||
|
||||
Use the five-level classification system to define section requirements:
|
||||
|
||||
```json
|
||||
"x-markitect-sections": {
|
||||
"SYNOPSIS": {
|
||||
"classification": "required",
|
||||
"content_instruction": "Brief command syntax",
|
||||
"error_message": "SYNOPSIS is mandatory"
|
||||
},
|
||||
"EXAMPLES": {
|
||||
"classification": "recommended",
|
||||
"warning_if_missing": "Examples improve usability"
|
||||
},
|
||||
"BUGS": {
|
||||
"classification": "optional"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Choose classifications based on importance:
|
||||
- **required** for essential sections (SYNOPSIS, DESCRIPTION)
|
||||
- **recommended** for important sections (EXAMPLES, SEE ALSO)
|
||||
- **optional** for nice-to-have sections (BUGS, AUTHORS)
|
||||
- **discouraged** for sections that should be elsewhere (DEPRECATED)
|
||||
- **improper** for sections that must not appear (TODO, INTERNAL_NOTES)
|
||||
|
||||
**Heading Patterns**
|
||||
|
||||
Use regex patterns for flexible heading validation:
|
||||
|
||||
```json
|
||||
"pattern": "^[A-Z][A-Z ]+$"
|
||||
```
|
||||
|
||||
Matches UPPERCASE section names while allowing variation.
|
||||
|
||||
**Progressive Refinement**
|
||||
|
||||
Start with loose constraints, tighten based on validation experience with real documents.
|
||||
|
||||
### Anti-Patterns
|
||||
|
||||
**Over-Specification**
|
||||
|
||||
Avoid schemas that are too specific:
|
||||
|
||||
```json
|
||||
"paragraphs": { "const": 47 }
|
||||
```
|
||||
|
||||
This requires exactly 47 paragraphs, which is too rigid for most use cases.
|
||||
|
||||
**Under-Specification**
|
||||
|
||||
Avoid schemas that validate nothing:
|
||||
|
||||
```json
|
||||
"paragraphs": { "minItems": 0 }
|
||||
```
|
||||
|
||||
Provide meaningful constraints that ensure document quality.
|
||||
|
||||
**Semantic Validation**
|
||||
|
||||
Schemas validate structure, not content. Don't expect schemas to validate:
|
||||
|
||||
- Correct grammar or spelling
|
||||
- Factual accuracy
|
||||
- Code correctness
|
||||
- Logical flow
|
||||
|
||||
Use other tools for semantic validation.
|
||||
|
||||
## INTEGRATION
|
||||
|
||||
### CI/CD Integration
|
||||
|
||||
Validate documentation in continuous integration:
|
||||
|
||||
```bash
|
||||
markitect validate README.md readme-schema.json --quiet
|
||||
exit_code=$?
|
||||
|
||||
if [ $exit_code -eq 0 ]; then
|
||||
echo "Documentation valid"
|
||||
else
|
||||
echo "Documentation validation failed"
|
||||
markitect validate README.md readme-schema.json --detailed-errors
|
||||
exit 1
|
||||
fi
|
||||
```
|
||||
|
||||
### Git Hooks
|
||||
|
||||
Pre-commit hook for automatic validation:
|
||||
|
||||
```bash
|
||||
changed_docs=$(git diff --cached --name-only --diff-filter=ACM | grep '.md$')
|
||||
|
||||
for doc in $changed_docs; do
|
||||
schema="${doc%.md}-schema.json"
|
||||
if [ -f "$schema" ]; then
|
||||
markitect validate "$doc" "$schema" || exit 1
|
||||
fi
|
||||
done
|
||||
```
|
||||
|
||||
### Build Systems
|
||||
|
||||
Makefile integration:
|
||||
|
||||
```makefile
|
||||
.PHONY: validate-docs
|
||||
validate-docs:
|
||||
@for doc in docs/*.md; do \
|
||||
markitect validate "$$doc" doc-schema.json || exit 1; \
|
||||
done
|
||||
|
||||
.PHONY: build
|
||||
build: validate-docs
|
||||
# Build process continues only if docs validate
|
||||
```
|
||||
|
||||
## EXAMPLES
|
||||
|
||||
### Generate Schema from Document
|
||||
|
||||
```bash
|
||||
markitect schema-generate examples/invoice.md --output invoice-schema.json
|
||||
```
|
||||
|
||||
### Store Schema for Reuse
|
||||
|
||||
```bash
|
||||
markitect schema-ingest invoice-schema.json
|
||||
markitect schema-list
|
||||
```
|
||||
|
||||
### Validate Single Document
|
||||
|
||||
```bash
|
||||
markitect validate draft-invoice.md invoice-schema.json
|
||||
|
||||
markitect validate draft-invoice.md invoice-schema.json --detailed-errors
|
||||
```
|
||||
|
||||
### Batch Validation
|
||||
|
||||
```bash
|
||||
for invoice in invoices/*.md; do
|
||||
markitect validate "$invoice" invoice-schema.json --quiet
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Invalid: $invoice"
|
||||
markitect validate "$invoice" invoice-schema.json --detailed-errors
|
||||
fi
|
||||
done
|
||||
```
|
||||
|
||||
### Template Generation
|
||||
|
||||
```bash
|
||||
markitect generate-stub invoice-schema.json --output new-invoice-template.md
|
||||
|
||||
cat new-invoice-template.md
|
||||
|
||||
markitect validate new-invoice-template.md invoice-schema.json
|
||||
```
|
||||
|
||||
### Schema Refinement Workflow
|
||||
|
||||
```bash
|
||||
markitect schema-generate example.md --output v1-schema.json
|
||||
|
||||
markitect validate test-doc.md v1-schema.json --detailed-errors
|
||||
|
||||
markitect schema-generate example.md --max-depth 2 --output v2-schema.json
|
||||
|
||||
markitect validate test-doc.md v2-schema.json
|
||||
```
|
||||
|
||||
### Schema with Classification System
|
||||
|
||||
Create a schema with section classifications and content control:
|
||||
|
||||
```json
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"title": "Technical Documentation Schema",
|
||||
"x-markitect-sections": {
|
||||
"OVERVIEW": {
|
||||
"classification": "required",
|
||||
"heading_level": 2,
|
||||
"content_instruction": "High-level description of the system",
|
||||
"min_paragraphs": 2,
|
||||
"error_message": "OVERVIEW section is required"
|
||||
},
|
||||
"EXAMPLES": {
|
||||
"classification": "recommended",
|
||||
"heading_level": 2,
|
||||
"min_code_blocks": 2,
|
||||
"warning_if_missing": "Examples help users understand usage"
|
||||
},
|
||||
"REFERENCES": {
|
||||
"classification": "optional",
|
||||
"heading_level": 2,
|
||||
"content_instruction": "External documentation and resources"
|
||||
},
|
||||
"TODO": {
|
||||
"classification": "improper",
|
||||
"error_message": "Remove TODO sections before publishing"
|
||||
}
|
||||
},
|
||||
"x-markitect-content-control": {
|
||||
"overview": {
|
||||
"discouraged_patterns": ["TODO", "FIXME"],
|
||||
"forbidden_patterns": ["password", "secret"],
|
||||
"content_quality": {
|
||||
"min_words": 100,
|
||||
"max_words": 500,
|
||||
"readability_target": "technical"
|
||||
}
|
||||
}
|
||||
},
|
||||
"properties": {
|
||||
"headings": {
|
||||
"properties": {
|
||||
"level_1": {"minItems": 1, "maxItems": 1},
|
||||
"level_2": {"minItems": 2, "maxItems": 20}
|
||||
}
|
||||
},
|
||||
"paragraphs": {"minItems": 10, "maxItems": 200},
|
||||
"code_blocks": {"minItems": 1}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Validate documents against this schema:
|
||||
|
||||
```bash
|
||||
# Missing required section = ERROR
|
||||
markitect validate doc-without-overview.md tech-schema.json
|
||||
# Result: INVALID - missing required section OVERVIEW
|
||||
|
||||
# Missing recommended section = WARNING
|
||||
markitect validate doc-without-examples.md tech-schema.json
|
||||
# Result: VALID (with warnings) - missing recommended section EXAMPLES
|
||||
|
||||
# Improper section present = ERROR
|
||||
markitect validate doc-with-todo.md tech-schema.json
|
||||
# Result: INVALID - improper section TODO must not be present
|
||||
```
|
||||
|
||||
## FILES
|
||||
|
||||
**\*.json**
|
||||
: JSON schema files defining document structure
|
||||
: Standard JSON Schema draft-07 format with MarkiTect extensions
|
||||
|
||||
**markitect.db**
|
||||
: Database storing ingested schemas
|
||||
: SQLite database in current directory or specified path
|
||||
|
||||
**.markitect.yml**
|
||||
: Configuration file for default schemas
|
||||
: YAML format with schema paths and validation rules
|
||||
|
||||
## EXIT STATUS
|
||||
|
||||
**0**
|
||||
: Success - document is valid
|
||||
|
||||
**1**
|
||||
: General error - file not found, invalid arguments
|
||||
|
||||
**2**
|
||||
: Configuration error - invalid schema file
|
||||
|
||||
**3**
|
||||
: Database error - schema storage/retrieval failed
|
||||
|
||||
**4**
|
||||
: Validation error - document does not conform to schema
|
||||
|
||||
## ENVIRONMENT
|
||||
|
||||
**MARKITECT_DATABASE**
|
||||
: Path to database file for schema storage
|
||||
: Default: markitect.db in current directory
|
||||
|
||||
**MARKITECT_SCHEMA_PATH**
|
||||
: Search path for schema files
|
||||
: Colon-separated list of directories
|
||||
|
||||
**MARKITECT_VALIDATION_STRICT**
|
||||
: Enable strict validation mode
|
||||
: Any non-empty value enables strict mode
|
||||
|
||||
## SEE ALSO
|
||||
|
||||
**markitect**(1), **json-schema**(7), **markdown-it**(7)
|
||||
|
||||
Related documentation:
|
||||
- JSON Schema Specification (https://json-schema.org/)
|
||||
- MarkiTect Schema Reference
|
||||
- AST Structure Documentation
|
||||
- Template System Guide
|
||||
|
||||
## LIMITATIONS
|
||||
|
||||
Schema validation has inherent limitations:
|
||||
|
||||
**Structure Only**
|
||||
|
||||
Schemas validate document structure, not content semantics. Cannot validate:
|
||||
- Factual correctness
|
||||
- Code functionality
|
||||
- Logical consistency
|
||||
- Language quality
|
||||
|
||||
**AST-Based**
|
||||
|
||||
Validation operates on parsed AST, not raw markdown. Some markdown formatting details may not be preserved or validated.
|
||||
|
||||
**Performance**
|
||||
|
||||
Large documents with complex schemas may have performance implications. AST caching mitigates this for repeated validations.
|
||||
|
||||
**Schema Complexity**
|
||||
|
||||
Very complex schemas can become difficult to maintain. Keep schemas as simple as possible while meeting requirements.
|
||||
|
||||
## BUGS
|
||||
|
||||
Report bugs at: https://github.com/markitect/markitect/issues
|
||||
|
||||
Known issues:
|
||||
- Schema generation from very large documents may be slow
|
||||
- Some edge cases in heading pattern matching
|
||||
- Limited support for custom markdown extensions
|
||||
|
||||
## AUTHORS
|
||||
|
||||
MarkiTect development team
|
||||
|
||||
Schema validation system designed for structured content management and documentation consistency.
|
||||
|
||||
## COPYRIGHT
|
||||
|
||||
Copyright (c) 2025 MarkiTect Project. Licensed under MIT License.
|
||||
|
||||
## VERSION
|
||||
|
||||
This manual documents schema validation in MarkiTect version 1.0 and later.
|
||||
309
examples/schemas/manpage-schema-v1.md
Normal file
309
examples/schemas/manpage-schema-v1.md
Normal file
@@ -0,0 +1,309 @@
|
||||
# Manpage Schema v1.0
|
||||
|
||||
**Schema ID:** `https://markitect.dev/schemas/manpage/v1`
|
||||
**Version:** 1.0.0
|
||||
**Status:** Stable
|
||||
**Created:** 2026-01-04
|
||||
**Document Types:** Manual pages, CLI documentation
|
||||
|
||||
## Overview
|
||||
|
||||
This schema validates Unix/Linux manual page documentation following standard conventions. Manual pages (man pages) are the traditional form of documentation for Unix commands and system calls.
|
||||
|
||||
## Typical Structure
|
||||
|
||||
A well-formed manual page includes:
|
||||
|
||||
1. **NAME** - Command name and one-line description
|
||||
2. **SYNOPSIS** - Command syntax showing all options
|
||||
3. **DESCRIPTION** - Detailed explanation of what the command does
|
||||
4. **OPTIONS** - Description of each command-line option
|
||||
5. **EXAMPLES** - Practical usage examples
|
||||
6. **SEE ALSO** - Related commands or documentation
|
||||
|
||||
## Usage
|
||||
|
||||
### Validate a Manpage
|
||||
|
||||
```bash
|
||||
markitect validate mycommand.1.md --schema manpage-schema-v1
|
||||
```
|
||||
|
||||
### Generate Manpage Template
|
||||
|
||||
```bash
|
||||
markitect generate-stub manpage-schema-v1.json --output newcommand.1.md
|
||||
```
|
||||
|
||||
### Refine Existing Schema
|
||||
|
||||
```bash
|
||||
markitect schema-refine manpage-schema-v1.json --loosen-counts
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
Complete examples can be found in:
|
||||
- [examples/manpages/markdown-schema-validation.1.md](../manpages/markdown-schema-validation.1.md)
|
||||
|
||||
## Validation Rules
|
||||
|
||||
### Required Sections (Level 2 Headings)
|
||||
|
||||
**NAME**
|
||||
- **Classification:** Required
|
||||
- **Content:** Command name in bold followed by brief description
|
||||
- **Format:** `**command** - one line description`
|
||||
- **Example:** `**markitect** - validate and analyze markdown documents`
|
||||
|
||||
**SYNOPSIS**
|
||||
- **Classification:** Required
|
||||
- **Content:** Command syntax with all options
|
||||
- **Min code blocks:** 1
|
||||
- **Max paragraphs:** 3
|
||||
- **Example:**
|
||||
```bash
|
||||
markitect [OPTIONS] COMMAND [ARGS]
|
||||
```
|
||||
|
||||
**DESCRIPTION**
|
||||
- **Classification:** Required
|
||||
- **Content:** Detailed explanation of the command
|
||||
- **Min paragraphs:** 2
|
||||
- **Min words:** 50
|
||||
|
||||
### Recommended Sections
|
||||
|
||||
**OPTIONS**
|
||||
- **Classification:** Recommended
|
||||
- **Content:** Definition list or table of command-line options
|
||||
- **Format:** Each option as `**--option** *type*` followed by description
|
||||
|
||||
**EXAMPLES**
|
||||
- **Classification:** Recommended
|
||||
- **Content:** Practical usage examples with explanations
|
||||
- **Min code blocks:** 1
|
||||
- **Benefit:** Greatly improves documentation usability
|
||||
|
||||
### Optional Sections
|
||||
|
||||
**ENVIRONMENT**
|
||||
- Environment variables affecting command behavior
|
||||
|
||||
**FILES**
|
||||
- Important files used or created by the command
|
||||
|
||||
**EXIT STATUS**
|
||||
- Explanation of exit codes
|
||||
|
||||
**BUGS**
|
||||
- Known issues or limitations
|
||||
|
||||
**AUTHORS**
|
||||
- Command authors and contributors
|
||||
|
||||
**SEE ALSO**
|
||||
- Related commands or documentation
|
||||
|
||||
## Schema Definition
|
||||
|
||||
```json
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"$id": "https://markitect.dev/schemas/manpage/v1",
|
||||
"version": "1.0.0",
|
||||
"title": "Unix Manual Page Schema",
|
||||
"description": "Schema for validating Unix/Linux manual page documentation",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"headings": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"level_1": {
|
||||
"type": "array",
|
||||
"description": "Document title (command name)",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"content": {
|
||||
"type": "string",
|
||||
"pattern": ".*"
|
||||
}
|
||||
}
|
||||
},
|
||||
"minItems": 1,
|
||||
"maxItems": 1
|
||||
},
|
||||
"level_2": {
|
||||
"type": "array",
|
||||
"description": "Section headings",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"content": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"NAME",
|
||||
"SYNOPSIS",
|
||||
"DESCRIPTION",
|
||||
"OPTIONS",
|
||||
"EXAMPLES",
|
||||
"ENVIRONMENT",
|
||||
"FILES",
|
||||
"EXIT STATUS",
|
||||
"BUGS",
|
||||
"AUTHORS",
|
||||
"SEE ALSO"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"minItems": 3,
|
||||
"maxItems": 20
|
||||
}
|
||||
},
|
||||
"required": ["level_1", "level_2"]
|
||||
},
|
||||
"paragraphs": {
|
||||
"type": "array",
|
||||
"description": "Paragraph content",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"content": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
}
|
||||
}
|
||||
},
|
||||
"minItems": 3
|
||||
},
|
||||
"code_blocks": {
|
||||
"type": "array",
|
||||
"description": "Code examples and command syntax",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"language": {
|
||||
"type": "string"
|
||||
},
|
||||
"content": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"minItems": 1
|
||||
}
|
||||
},
|
||||
"required": ["headings", "paragraphs"],
|
||||
"x-markitect-sections": {
|
||||
"NAME": {
|
||||
"classification": "required",
|
||||
"heading_level": 2,
|
||||
"content_instruction": "Command name in bold followed by brief description",
|
||||
"pattern": "\\*\\*[a-z-]+\\*\\*.*",
|
||||
"error_if_missing": "NAME section is required in all manual pages"
|
||||
},
|
||||
"SYNOPSIS": {
|
||||
"classification": "required",
|
||||
"heading_level": 2,
|
||||
"content_instruction": "Command syntax showing all options and arguments",
|
||||
"min_code_blocks": 1,
|
||||
"error_if_missing": "SYNOPSIS section is required to show command usage"
|
||||
},
|
||||
"DESCRIPTION": {
|
||||
"classification": "required",
|
||||
"heading_level": 2,
|
||||
"content_instruction": "Detailed explanation of what the command does and when to use it",
|
||||
"min_paragraphs": 2,
|
||||
"min_words": 50,
|
||||
"error_if_missing": "DESCRIPTION section is required for detailed explanation"
|
||||
},
|
||||
"OPTIONS": {
|
||||
"classification": "recommended",
|
||||
"heading_level": 2,
|
||||
"content_instruction": "Description of each command-line option with syntax and explanation",
|
||||
"warning_if_missing": "OPTIONS section recommended for commands with options"
|
||||
},
|
||||
"EXAMPLES": {
|
||||
"classification": "recommended",
|
||||
"heading_level": 2,
|
||||
"content_instruction": "Practical usage examples with explanations",
|
||||
"min_code_blocks": 1,
|
||||
"warning_if_missing": "EXAMPLES greatly improve documentation usability"
|
||||
},
|
||||
"ENVIRONMENT": {
|
||||
"classification": "optional",
|
||||
"heading_level": 2,
|
||||
"content_instruction": "Environment variables that affect command behavior"
|
||||
},
|
||||
"FILES": {
|
||||
"classification": "optional",
|
||||
"heading_level": 2,
|
||||
"content_instruction": "Important files used or created by the command"
|
||||
},
|
||||
"SEE ALSO": {
|
||||
"classification": "optional",
|
||||
"heading_level": 2,
|
||||
"content_instruction": "Related commands or documentation references"
|
||||
}
|
||||
},
|
||||
"x-markitect-content-control": {
|
||||
"name_section": {
|
||||
"required_pattern": "\\*\\*[a-z-]+\\*\\*",
|
||||
"description": "Command name must be in bold",
|
||||
"example": "**markitect** - validate and analyze markdown documents"
|
||||
},
|
||||
"synopsis_section": {
|
||||
"min_code_blocks": 1,
|
||||
"code_block_language": "bash",
|
||||
"description": "Must include at least one code block showing command syntax"
|
||||
},
|
||||
"description_section": {
|
||||
"min_paragraphs": 2,
|
||||
"min_words": 50,
|
||||
"description": "Detailed description with at least 50 words across 2+ paragraphs"
|
||||
}
|
||||
},
|
||||
"x-markitect-metadata": {
|
||||
"schema-type": "document-schema",
|
||||
"domain": "manpage",
|
||||
"document-types": ["manual-page", "man-page", "cli-documentation"],
|
||||
"version": "1.0.0",
|
||||
"author": "MarkiTect Project",
|
||||
"created": "2026-01-04",
|
||||
"updated": "2026-01-04",
|
||||
"example": "examples/manpages/markdown-schema-validation.1.md",
|
||||
"supersedes": null,
|
||||
"superseded-by": null
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Version History
|
||||
|
||||
### v1.0.0 (2026-01-04)
|
||||
- Initial stable release
|
||||
- Validates standard manpage sections
|
||||
- Classification system (required/recommended/optional)
|
||||
- Content control for NAME, SYNOPSIS, DESCRIPTION
|
||||
- MarkiTect extensions for improved validation
|
||||
|
||||
## Future Enhancements
|
||||
|
||||
Planned for v2.0:
|
||||
- Multi-language support (internationalization)
|
||||
- Extended sections (DIAGNOSTICS, SECURITY, STANDARDS)
|
||||
- Cross-reference validation
|
||||
- Version-specific section variants (man1, man5, man8)
|
||||
|
||||
## Contributing
|
||||
|
||||
To suggest improvements to this schema:
|
||||
1. Open an issue describing the enhancement
|
||||
2. Provide example documents demonstrating the need
|
||||
3. Propose specific schema changes
|
||||
|
||||
## License
|
||||
|
||||
This schema is part of the MarkiTect project and follows the same license.
|
||||
41
examples/templates/adr-template.md
Normal file
41
examples/templates/adr-template.md
Normal file
@@ -0,0 +1,41 @@
|
||||
<!-- Generated from schema: markitect/schemas/adr-schema-v1.0.md -->
|
||||
|
||||
# Architecture Decision Record Schema with Classifications
|
||||
|
||||
TODO: Add content for introduction section.
|
||||
|
||||
## Introduction
|
||||
|
||||
TODO: Add content for section_level_2 section.
|
||||
|
||||
## Main Content
|
||||
|
||||
TODO: Add content for section_level_2 section.
|
||||
|
||||
## Conclusion
|
||||
|
||||
TODO: Add content for section_level_2 section.
|
||||
|
||||
## Summary
|
||||
|
||||
TODO: Add content for section_level_2 section.
|
||||
|
||||
## Overview
|
||||
|
||||
TODO: Add content for section_level_2 section.
|
||||
|
||||
## Section 6
|
||||
|
||||
TODO: Add content for section_level_2 section.
|
||||
|
||||
### Background
|
||||
|
||||
TODO: Add content for section_level_3 section.
|
||||
|
||||
### Analysis
|
||||
|
||||
TODO: Add content for section_level_3 section.
|
||||
|
||||
### Implementation
|
||||
|
||||
TODO: Add content for section_level_3 section.
|
||||
315
examples/terminology/README.md
Normal file
315
examples/terminology/README.md
Normal file
@@ -0,0 +1,315 @@
|
||||
# Terminology Document Example
|
||||
|
||||
This example demonstrates how to use MarkiTect schemas to validate terminology and glossary documents.
|
||||
|
||||
## Overview
|
||||
|
||||
Terminology documents (glossaries, dictionaries, lexicons) benefit from consistent structure and validation. This example shows how to:
|
||||
|
||||
1. Structure terminology documents with clear categories and term definitions
|
||||
2. Validate terminology documents using JSON schemas
|
||||
3. Use MarkiTect's schema extensions for content control
|
||||
|
||||
## Files
|
||||
|
||||
- **terminology-example.md** - Example terminology document with proper structure
|
||||
- **Schema**: `terminology-schema-v1.0.md` (in `markitect/schemas/`)
|
||||
- **README.md** - This file
|
||||
|
||||
The terminology schema now follows the schema-of-schemas standard with markdown format and embedded JSON.
|
||||
|
||||
## Terminology Document Structure
|
||||
|
||||
A well-structured terminology document includes:
|
||||
|
||||
### Required Elements
|
||||
|
||||
1. **Main Title (Level 1 Heading)**
|
||||
- Should include keywords: "Terminology", "Glossary", "Terms", or "Definitions"
|
||||
|
||||
2. **Category Sections (Level 2 Headings)**
|
||||
- Organize terms into logical groups
|
||||
- Examples: "Core Concepts", "Document Types", "Process Terms"
|
||||
|
||||
3. **Term Definitions (Level 3 Headings)**
|
||||
- Each term as a level 3 heading
|
||||
- Followed by structured content
|
||||
|
||||
### Term Structure
|
||||
|
||||
Each term should include:
|
||||
|
||||
**Required:**
|
||||
- **Definition:** Clear, concise explanation of the term
|
||||
|
||||
**Optional (but recommended):**
|
||||
- **Synonyms:** Alternative names or abbreviations
|
||||
- **Related Terms:** Links to related concepts
|
||||
- **Example:** Practical usage example
|
||||
- **Use Cases:** Common scenarios
|
||||
- **Format:** For document type terms
|
||||
- **Components:** For complex concepts
|
||||
- **Steps:** For process terms
|
||||
|
||||
## Usage
|
||||
|
||||
### List Available Schemas
|
||||
|
||||
View all registered schemas (including terminology schema):
|
||||
|
||||
```bash
|
||||
markitect schema-list
|
||||
```
|
||||
|
||||
You should see `terminology-schema-v1.0.md` listed with a number.
|
||||
|
||||
### Validate Using the Schema
|
||||
|
||||
The terminology schema is registered in MarkiTect's database. You can validate using multiple methods:
|
||||
|
||||
```bash
|
||||
# By schema number (if terminology schema is #4 in the list)
|
||||
markitect schema-validate 4
|
||||
|
||||
# By schema filename (from registry)
|
||||
markitect schema-validate terminology-schema-v1.0.md
|
||||
|
||||
# Validate a specific document file
|
||||
markitect validate my-glossary.md --schema terminology-schema-v1.0.md
|
||||
|
||||
# Or use the local file path directly
|
||||
markitect validate my-glossary.md --schema ./markitect/schemas/terminology-schema-v1.0.md
|
||||
```
|
||||
|
||||
### Validate with Detailed Errors
|
||||
|
||||
```bash
|
||||
markitect schema-validate terminology-schema-v1.0.md --detailed-errors
|
||||
```
|
||||
|
||||
### Batch Validation
|
||||
|
||||
Validate multiple schemas at once:
|
||||
|
||||
```bash
|
||||
# Validate all schemas
|
||||
markitect schema-validate --all
|
||||
|
||||
# Validate a range
|
||||
markitect schema-validate 1-4
|
||||
|
||||
# Validate specific schemas
|
||||
markitect schema-validate 2,4
|
||||
```
|
||||
|
||||
### View the Schema
|
||||
|
||||
Examine the terminology schema:
|
||||
|
||||
```bash
|
||||
# Get from registry
|
||||
markitect schema-get terminology-schema-v1.0.md
|
||||
|
||||
# Or view the markdown file directly
|
||||
cat markitect/schemas/terminology-schema-v1.0.md
|
||||
```
|
||||
|
||||
## Schema Features
|
||||
|
||||
This schema demonstrates several MarkiTect features:
|
||||
|
||||
### 1. Structural Validation
|
||||
|
||||
- Enforces consistent heading hierarchy (H1 → H2 → H3)
|
||||
- Validates minimum term count
|
||||
- Ensures proper document structure
|
||||
|
||||
### 2. Content Pattern Validation
|
||||
|
||||
- Validates title pattern (must contain terminology-related keywords)
|
||||
- Checks for required field labels (Definition:, Synonyms:, etc.)
|
||||
- Enforces consistent formatting
|
||||
|
||||
### 3. MarkiTect Extensions
|
||||
|
||||
The schema uses MarkiTect-specific extensions:
|
||||
|
||||
#### `x-markitect-sections`
|
||||
Defines section classifications and requirements:
|
||||
- `document_title` (required)
|
||||
- `category_sections` (required, min 1)
|
||||
- `term_definitions` (required, min 1)
|
||||
|
||||
#### `x-markitect-content-control`
|
||||
Specifies content requirements:
|
||||
- Required vs optional components
|
||||
- Content quality metrics (word counts)
|
||||
- Content instructions for authors
|
||||
|
||||
#### `x-markitect-validation-rules`
|
||||
Custom validation rules:
|
||||
- Minimum term count (3 required, 10+ recommended)
|
||||
- Category balance (min 2 terms per category)
|
||||
- Definition quality checks
|
||||
- Consistency validation
|
||||
|
||||
## Best Practices
|
||||
|
||||
### 1. Use Consistent Field Labels
|
||||
|
||||
Always use the same labels for metadata:
|
||||
```markdown
|
||||
**Definition:** ...
|
||||
**Synonyms:** ...
|
||||
**Related Terms:** ...
|
||||
```
|
||||
|
||||
### 2. Write Clear Definitions
|
||||
|
||||
- Start with the term's primary meaning
|
||||
- Use 10-200 words
|
||||
- Be self-contained (don't require reading other terms)
|
||||
- Avoid circular definitions
|
||||
|
||||
### 3. Group Related Terms
|
||||
|
||||
Organize terms into logical categories:
|
||||
- Core Concepts
|
||||
- Document Types
|
||||
- Process Terms
|
||||
- Quality Attributes
|
||||
- Deprecated Terms
|
||||
|
||||
### 4. Include Examples
|
||||
|
||||
Add practical examples for complex terms:
|
||||
```markdown
|
||||
**Example:**
|
||||
\`\`\`markdown
|
||||
# Heading
|
||||
Paragraph text
|
||||
\`\`\`
|
||||
```
|
||||
|
||||
### 5. Link Related Terms
|
||||
|
||||
Use **Related Terms:** to create a terminology graph:
|
||||
```markdown
|
||||
**Related Terms:** Parser, Token, Node
|
||||
```
|
||||
|
||||
## Extending the Schema
|
||||
|
||||
You can customize the schema for your project:
|
||||
|
||||
### Add Custom Field Labels
|
||||
|
||||
Extend the `bold_text` enum:
|
||||
```json
|
||||
"enum": [
|
||||
"Definition:",
|
||||
"Synonyms:",
|
||||
"Your Custom Label:"
|
||||
]
|
||||
```
|
||||
|
||||
### Adjust Quality Metrics
|
||||
|
||||
Modify content quality requirements:
|
||||
```json
|
||||
"content_quality": {
|
||||
"min_words_per_definition": 20,
|
||||
"max_words_per_definition": 300,
|
||||
"readability_target": "business"
|
||||
}
|
||||
```
|
||||
|
||||
### Add Domain-Specific Validation
|
||||
|
||||
Include specialized validation rules:
|
||||
```json
|
||||
"x-markitect-validation-rules": {
|
||||
"domain_specific": {
|
||||
"require_acronym_expansion": true,
|
||||
"require_source_citations": true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Use Cases
|
||||
|
||||
### Documentation Projects
|
||||
|
||||
- Software project glossaries
|
||||
- API terminology reference
|
||||
- Architecture decision records (ADR) glossary
|
||||
- Domain-driven design (DDD) ubiquitous language
|
||||
|
||||
### Technical Writing
|
||||
|
||||
- Standards documentation
|
||||
- Compliance documentation (ISO, SOC2)
|
||||
- Technical specifications
|
||||
- Research papers
|
||||
|
||||
### Knowledge Management
|
||||
|
||||
- Company wikis
|
||||
- Team handbooks
|
||||
- Onboarding documentation
|
||||
- Training materials
|
||||
|
||||
## Integration with CI/CD
|
||||
|
||||
### Pre-commit Hook
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
# .git/hooks/pre-commit
|
||||
markitect validate docs/glossary.md --schema terminology-schema-v1.0.md
|
||||
```
|
||||
|
||||
### GitHub Actions
|
||||
|
||||
```yaml
|
||||
name: Validate Terminology
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
validate:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Install MarkiTect
|
||||
run: pip install markitect
|
||||
- name: Validate Glossary
|
||||
run: |
|
||||
markitect validate docs/glossary.md \
|
||||
--schema terminology-schema-v1.0.md \
|
||||
--detailed-errors
|
||||
```
|
||||
|
||||
## Related Examples
|
||||
|
||||
- **manpages/** - Manual page documentation validation
|
||||
- **templates/** - Document template examples
|
||||
- **design-patterns/** - Software pattern documentation
|
||||
|
||||
## Learn More
|
||||
|
||||
- [Schema Extensions Specification](../../docs/specifications/schema-extensions-spec.md)
|
||||
- [MarkiTect Documentation](../../README.md)
|
||||
- [JSON Schema Documentation](https://json-schema.org/)
|
||||
|
||||
## Contributing
|
||||
|
||||
To improve this example:
|
||||
|
||||
1. Add more terms to demonstrate edge cases
|
||||
2. Enhance the schema with additional validation rules
|
||||
3. Create alternative terminology document styles
|
||||
4. Add multilingual terminology examples
|
||||
|
||||
## License
|
||||
|
||||
This example is part of the MarkiTect project and follows the same license.
|
||||
91
examples/terminology/terminology-example.md
Normal file
91
examples/terminology/terminology-example.md
Normal file
@@ -0,0 +1,91 @@
|
||||
# Project Terminology
|
||||
|
||||
A glossary of key terms and concepts for this project.
|
||||
|
||||
## Core Concepts
|
||||
|
||||
### Abstract Syntax Tree
|
||||
|
||||
**Definition:** A tree representation of the abstract syntactic structure of source code or markup, where each node represents a construct occurring in the source.
|
||||
|
||||
**Synonyms:** AST, Parse Tree
|
||||
|
||||
**Related Terms:** Parser, Token, Node
|
||||
|
||||
**Example:**
|
||||
```markdown
|
||||
# Heading
|
||||
Paragraph text
|
||||
```
|
||||
|
||||
The AST representation would include nodes for heading (level 1) and paragraph elements.
|
||||
|
||||
### Schema Validation
|
||||
|
||||
**Definition:** The process of verifying that a document's structure conforms to a predefined schema specification.
|
||||
|
||||
**Synonyms:** Structural Validation, Schema Conformance
|
||||
|
||||
**Related Terms:** JSON Schema, Validator, Metaschema
|
||||
|
||||
**Use Cases:**
|
||||
- Ensuring documentation completeness
|
||||
- Enforcing content standards
|
||||
- Automated quality checks
|
||||
|
||||
## Document Types
|
||||
|
||||
### Manpage
|
||||
|
||||
**Definition:** A manual page document following Unix/Linux documentation conventions, typically including sections like SYNOPSIS, DESCRIPTION, and OPTIONS.
|
||||
|
||||
**Format:** Markdown with specific heading structure
|
||||
|
||||
**Related Terms:** Documentation, Manual, Help Text
|
||||
|
||||
### Blueprint
|
||||
|
||||
**Definition:** A template specification that combines schemas, content instructions, and data templates for generating documents.
|
||||
|
||||
**Components:**
|
||||
- Schema references
|
||||
- Content model
|
||||
- Data schema
|
||||
- Generation rules
|
||||
|
||||
## Process Terms
|
||||
|
||||
### Schema Refinement
|
||||
|
||||
**Definition:** The process of transforming a rigid, auto-generated schema into a flexible, classification-aware schema with content guidance.
|
||||
|
||||
**Steps:**
|
||||
1. Analyze existing schema for rigidity
|
||||
2. Loosen exact constraints to ranges
|
||||
3. Add classification metadata
|
||||
4. Include content instructions
|
||||
|
||||
**Tools:** `markitect schema-analyze`, `markitect schema-refine`
|
||||
|
||||
## Quality Attributes
|
||||
|
||||
### Classification Levels
|
||||
|
||||
**Definition:** A hierarchical system for categorizing document elements based on their importance and requirements.
|
||||
|
||||
**Levels:**
|
||||
- **Required**: Must be present (validation fails if missing)
|
||||
- **Recommended**: Should be present (warning if missing)
|
||||
- **Optional**: May be present (no impact)
|
||||
- **Discouraged**: Should not be present (warning if present)
|
||||
- **Improper**: Must not be present (validation fails if present)
|
||||
|
||||
## Deprecated Terms
|
||||
|
||||
### Rigid Schema
|
||||
|
||||
**Status:** DEPRECATED - Use "Unrefined Schema" instead
|
||||
|
||||
**Definition:** A schema with exact count constraints that make it unusable as a pattern.
|
||||
|
||||
**Migration:** Use schema refinement tools to convert to flexible schemas.
|
||||
214
examples/terminology/terminology-schema.json
Normal file
214
examples/terminology/terminology-schema.json
Normal file
@@ -0,0 +1,214 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"$id": "https://markitect.dev/schemas/terminology-v1.json",
|
||||
"title": "Terminology Document Schema",
|
||||
"description": "Schema for validating terminology and glossary documents with consistent structure",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"headings": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"level_1": {
|
||||
"type": "array",
|
||||
"description": "Main document title",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"content": {
|
||||
"type": "string",
|
||||
"pattern": ".*(Terminology|Glossary|Terms|Definitions).*"
|
||||
}
|
||||
}
|
||||
},
|
||||
"minItems": 1,
|
||||
"maxItems": 1
|
||||
},
|
||||
"level_2": {
|
||||
"type": "array",
|
||||
"description": "Category headings (Core Concepts, Document Types, etc.)",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"content": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
}
|
||||
}
|
||||
},
|
||||
"minItems": 1,
|
||||
"maxItems": 20
|
||||
},
|
||||
"level_3": {
|
||||
"type": "array",
|
||||
"description": "Individual term headings",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"content": {
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
"description": "Term name - should be title case"
|
||||
}
|
||||
}
|
||||
},
|
||||
"minItems": 1
|
||||
}
|
||||
},
|
||||
"required": ["level_1", "level_2", "level_3"]
|
||||
},
|
||||
"paragraphs": {
|
||||
"type": "array",
|
||||
"description": "Content paragraphs including definitions and descriptions",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"content": {
|
||||
"type": "string",
|
||||
"minLength": 10
|
||||
}
|
||||
}
|
||||
},
|
||||
"minItems": 3
|
||||
},
|
||||
"bold_text": {
|
||||
"type": "array",
|
||||
"description": "Bold text used for field labels (Definition, Synonyms, etc.)",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"content": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"Definition:",
|
||||
"Synonyms:",
|
||||
"Related Terms:",
|
||||
"Example:",
|
||||
"Examples:",
|
||||
"Use Cases:",
|
||||
"Usage:",
|
||||
"Format:",
|
||||
"Components:",
|
||||
"Steps:",
|
||||
"Tools:",
|
||||
"Levels:",
|
||||
"Status:",
|
||||
"Migration:",
|
||||
"Required:",
|
||||
"Recommended:",
|
||||
"Optional:",
|
||||
"Discouraged:",
|
||||
"Improper:"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"minItems": 1
|
||||
}
|
||||
},
|
||||
"required": ["headings", "paragraphs"],
|
||||
"x-markitect-sections": {
|
||||
"document_title": {
|
||||
"classification": "required",
|
||||
"heading_level": 1,
|
||||
"content_instruction": "Main title should include words like 'Terminology', 'Glossary', or 'Definitions'",
|
||||
"pattern": ".*(Terminology|Glossary|Terms|Definitions).*"
|
||||
},
|
||||
"category_sections": {
|
||||
"classification": "required",
|
||||
"heading_level": 2,
|
||||
"min_sections": 1,
|
||||
"content_instruction": "Organize terms into logical categories (e.g., Core Concepts, Document Types, Process Terms)"
|
||||
},
|
||||
"term_definitions": {
|
||||
"classification": "required",
|
||||
"heading_level": 3,
|
||||
"min_sections": 1,
|
||||
"content_instruction": "Each term should be a level 3 heading followed by its definition and optional metadata"
|
||||
}
|
||||
},
|
||||
"x-markitect-content-control": {
|
||||
"term_structure": {
|
||||
"required_components": [
|
||||
{
|
||||
"label": "Definition:",
|
||||
"type": "bold_text",
|
||||
"description": "Clear, concise definition of the term"
|
||||
}
|
||||
],
|
||||
"optional_components": [
|
||||
{
|
||||
"label": "Synonyms:",
|
||||
"type": "bold_text",
|
||||
"description": "Alternative names or abbreviations"
|
||||
},
|
||||
{
|
||||
"label": "Related Terms:",
|
||||
"type": "bold_text",
|
||||
"description": "Links to related concepts"
|
||||
},
|
||||
{
|
||||
"label": "Example:",
|
||||
"type": "bold_text_or_code",
|
||||
"description": "Practical example demonstrating the term"
|
||||
},
|
||||
{
|
||||
"label": "Use Cases:",
|
||||
"type": "list",
|
||||
"description": "Common scenarios where term applies"
|
||||
}
|
||||
],
|
||||
"content_quality": {
|
||||
"min_words_per_definition": 10,
|
||||
"max_words_per_definition": 200,
|
||||
"readability_target": "technical"
|
||||
},
|
||||
"content_instructions": [
|
||||
"Start each term with a level 3 heading containing the term name",
|
||||
"Follow immediately with 'Definition:' in bold",
|
||||
"Provide a clear, self-contained definition",
|
||||
"Add optional fields (Synonyms, Related Terms, Examples) as needed",
|
||||
"Use consistent formatting across all terms",
|
||||
"Group related terms under category headings (level 2)"
|
||||
]
|
||||
},
|
||||
"definition_pattern": {
|
||||
"description": "Each definition should follow: Term heading (###) → Definition: (bold) → Definition text",
|
||||
"validation": {
|
||||
"heading_level_3_followed_by": "bold_text_starting_with_Definition",
|
||||
"definition_length": {
|
||||
"min_words": 10,
|
||||
"max_words": 200
|
||||
}
|
||||
}
|
||||
},
|
||||
"deprecated_terms": {
|
||||
"classification": "optional",
|
||||
"heading_level": 2,
|
||||
"content_instruction": "Optional section for deprecated terms with migration guidance",
|
||||
"required_fields": [
|
||||
"Status: DEPRECATED",
|
||||
"Migration:"
|
||||
]
|
||||
}
|
||||
},
|
||||
"x-markitect-validation-rules": {
|
||||
"term_count": {
|
||||
"min": 3,
|
||||
"recommended_min": 10,
|
||||
"description": "Terminology document should define at least 3 terms, 10+ recommended"
|
||||
},
|
||||
"category_balance": {
|
||||
"description": "Each category should have at least 2 terms",
|
||||
"min_terms_per_category": 2
|
||||
},
|
||||
"definition_quality": {
|
||||
"all_terms_must_have_definition": true,
|
||||
"definition_must_follow_term_heading": true,
|
||||
"definition_min_words": 10
|
||||
},
|
||||
"consistency": {
|
||||
"use_consistent_field_labels": true,
|
||||
"maintain_heading_hierarchy": true
|
||||
}
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user