|
13 | 13 | import validate_planning_docs # noqa: E402 |
14 | 14 |
|
15 | 15 |
|
| 16 | +VALID_TEMPLATE = """--- |
| 17 | +title: "Newsletter" |
| 18 | +doc_type: task-template |
| 19 | +schema_version: 1 |
| 20 | +source: "backend/scripts/seed-templates.ts" |
| 21 | +systems: |
| 22 | + - dataops |
| 23 | + - datatasks |
| 24 | +tags: |
| 25 | + - task-template |
| 26 | + - newsletter |
| 27 | +--- |
| 28 | +
|
| 29 | +# Newsletter |
| 30 | +
|
| 31 | +<!-- sop-section-start: summary --> |
| 32 | +## Summary |
| 33 | +<!-- sop-section-start: purpose --> |
| 34 | +## Purpose |
| 35 | +<!-- sop-section-start: references --> |
| 36 | +## References |
| 37 | +<!-- sop-section-start: required-card-links --> |
| 38 | +## Required Card Links |
| 39 | +<!-- sop-section-start: task-definitions --> |
| 40 | +## Task Definitions |
| 41 | +
|
| 42 | +| # | Ref ID | Phase | Offset | Owner | Operator action | Context | Proof / closure | Waiting / follow-up | |
| 43 | +| - | - | - | -: | - | - | - | - | - | |
| 44 | +| 1 | `create-document` | intake | -14 | owner | Create document | doc.id | url: Document | | |
| 45 | +""" |
| 46 | + |
| 47 | +INVALID_TEMPLATE = """--- |
| 48 | +title: "Invalid" |
| 49 | +doc_type: template |
| 50 | +schema_version: 2 |
| 51 | +source: "wrong-place.ts" |
| 52 | +systems: |
| 53 | + - dataops |
| 54 | +tags: |
| 55 | + - task-template |
| 56 | +--- |
| 57 | +
|
| 58 | +# Invalid |
| 59 | +""" |
| 60 | + |
| 61 | + |
16 | 62 | def test_current_repo_planning_docs_contract_passes(): |
17 | 63 | assert validate_planning_docs.validate(REPO_ROOT) == [] |
18 | 64 |
|
@@ -121,3 +167,55 @@ def test_task_template_accepts_richer_operator_workflow_table(tmp_path): |
121 | 167 | violations = validate_planning_docs.validate_task_templates(tmp_path) |
122 | 168 |
|
123 | 169 | assert violations == [] |
| 170 | + |
| 171 | + |
| 172 | +def test_task_template_paths_are_stable_across_corpus_layouts(tmp_path, monkeypatch): |
| 173 | + layouts = { |
| 174 | + "repository-local": ( |
| 175 | + tmp_path / "repository-local" / "app" / "content", |
| 176 | + tmp_path / "repository-local" / "app", |
| 177 | + ), |
| 178 | + ".knowledge": ( |
| 179 | + tmp_path / "dot-knowledge" / "app" / ".knowledge" / "content", |
| 180 | + tmp_path / "dot-knowledge" / "app", |
| 181 | + ), |
| 182 | + "configured-external": ( |
| 183 | + tmp_path / "configured-external" / "corpus" / "content", |
| 184 | + tmp_path / "configured-external" / "app", |
| 185 | + ), |
| 186 | + "sibling-style": ( |
| 187 | + tmp_path / "sibling-style" / "dataops-knowledge" / "content", |
| 188 | + tmp_path / "sibling-style" / "differently-named-app", |
| 189 | + ), |
| 190 | + } |
| 191 | + results = {} |
| 192 | + |
| 193 | + for layout, (content_root, app_root) in layouts.items(): |
| 194 | + templates_dir = content_root / "tasks" / "templates" |
| 195 | + templates_dir.mkdir(parents=True) |
| 196 | + (templates_dir / "newsletter.md").write_text(VALID_TEMPLATE, encoding="utf-8") |
| 197 | + |
| 198 | + if layout == "configured-external": |
| 199 | + monkeypatch.setenv("DATAOPS_CONTENT_ROOT", str(content_root)) |
| 200 | + else: |
| 201 | + monkeypatch.delenv("DATAOPS_CONTENT_ROOT", raising=False) |
| 202 | + |
| 203 | + assert validate_planning_docs.validate_task_templates(app_root) == [] |
| 204 | + |
| 205 | + newsletter_path = templates_dir / "newsletter.md" |
| 206 | + newsletter_path.write_text( |
| 207 | + INVALID_TEMPLATE.replace('title: "Invalid"', 'title: "Newsletter"'), |
| 208 | + encoding="utf-8", |
| 209 | + ) |
| 210 | + violations = validate_planning_docs.validate_task_templates(app_root) |
| 211 | + |
| 212 | + assert violations |
| 213 | + assert all(violation.startswith("content/tasks/templates/") for violation in violations) |
| 214 | + assert not any(str(app_root) in violation for violation in violations) |
| 215 | + assert any( |
| 216 | + violation == "content/tasks/templates/newsletter.md: doc_type must be task-template" |
| 217 | + for violation in violations |
| 218 | + ) |
| 219 | + results[layout] = tuple(violations) |
| 220 | + |
| 221 | + assert len(set(results.values())) == 1 |
0 commit comments