fix: read owner/cadence from properties in ai-context

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Test
2026-03-18 01:58:33 +01:00
parent e6b3278fea
commit e1c545220f
5 changed files with 59 additions and 17 deletions

View File

@@ -567,7 +567,11 @@ mod tests {
let entry = crate::vault::parse_md_file(&vault_path.join("AGENTS.md")).unwrap();
// No frontmatter title → extracted from H1 heading
assert!(entry.title.contains("Vault Instructions"), "title should come from H1: {}", entry.title);
assert!(
entry.title.contains("Vault Instructions"),
"title should come from H1: {}",
entry.title
);
// Config files have no frontmatter type field — type is None
assert_eq!(entry.is_a, None);
}

View File

@@ -76,8 +76,14 @@ fn test_parse_full_frontmatter_scalars() {
let dir = TempDir::new().unwrap();
let entry = parse_test_entry(&dir, "laputa.md", FULL_FM_CONTENT);
assert_eq!(entry.status, Some("Active".to_string()));
assert_eq!(entry.properties.get("Owner").and_then(|v| v.as_str()), Some("Luca"));
assert_eq!(entry.properties.get("Cadence").and_then(|v| v.as_str()), Some("Weekly"));
assert_eq!(
entry.properties.get("Owner").and_then(|v| v.as_str()),
Some("Luca")
);
assert_eq!(
entry.properties.get("Cadence").and_then(|v| v.as_str()),
Some("Weekly")
);
}
#[test]
@@ -509,7 +515,10 @@ fn test_created_at_from_filesystem() {
let entry = parse_md_file(&dir.path().join("test.md")).unwrap();
// created_at should be set from filesystem metadata (not None)
assert!(entry.created_at.is_some(), "created_at should come from filesystem");
assert!(
entry.created_at.is_some(),
"created_at should come from filesystem"
);
}
// --- Type relationship tests ---
@@ -806,8 +815,14 @@ Priority: High
entry.properties.get("Priority").and_then(|v| v.as_str()),
Some("High")
);
assert_eq!(entry.properties.get("Owner").and_then(|v| v.as_str()), Some("Luca"));
assert_eq!(entry.properties.get("Cadence").and_then(|v| v.as_str()), Some("Weekly"));
assert_eq!(
entry.properties.get("Owner").and_then(|v| v.as_str()),
Some("Luca")
);
assert_eq!(
entry.properties.get("Cadence").and_then(|v| v.as_str()),
Some("Weekly")
);
}
#[test]
@@ -1058,7 +1073,10 @@ fn test_single_element_array_owner_unwraps_to_scalar() {
let dir = TempDir::new().unwrap();
let content = "---\ntype: Responsibility\nOwner:\n - Luca\n---\n# Test\n";
let entry = parse_test_entry(&dir, "test.md", content);
assert_eq!(entry.properties.get("Owner").and_then(|v| v.as_str()), Some("Luca"));
assert_eq!(
entry.properties.get("Owner").and_then(|v| v.as_str()),
Some("Luca")
);
assert_eq!(entry.is_a, Some("Responsibility".to_string()));
}
@@ -1067,7 +1085,10 @@ fn test_single_element_array_cadence_unwraps_to_scalar() {
let dir = TempDir::new().unwrap();
let content = "---\ntype: Procedure\nCadence:\n - Weekly\n---\n# Test\n";
let entry = parse_test_entry(&dir, "test.md", content);
assert_eq!(entry.properties.get("Cadence").and_then(|v| v.as_str()), Some("Weekly"));
assert_eq!(
entry.properties.get("Cadence").and_then(|v| v.as_str()),
Some("Weekly")
);
assert_eq!(entry.is_a, Some("Procedure".to_string()));
}
@@ -1085,8 +1106,14 @@ fn test_scalar_fields_unchanged() {
let dir = TempDir::new().unwrap();
let content = "---\ntype: Project\nOwner: Luca\nCadence: Daily\nStatus: Done\n---\n# Test\n";
let entry = parse_test_entry(&dir, "test.md", content);
assert_eq!(entry.properties.get("Owner").and_then(|v| v.as_str()), Some("Luca"));
assert_eq!(entry.properties.get("Cadence").and_then(|v| v.as_str()), Some("Daily"));
assert_eq!(
entry.properties.get("Owner").and_then(|v| v.as_str()),
Some("Luca")
);
assert_eq!(
entry.properties.get("Cadence").and_then(|v| v.as_str()),
Some("Daily")
);
assert_eq!(entry.status, Some("Done".to_string()));
}

View File

@@ -358,17 +358,26 @@ mod tests {
#[test]
fn test_extract_title_fallback_to_filename() {
assert_eq!(extract_title(None, "", "fallback-title.md"), "Fallback Title");
assert_eq!(
extract_title(None, "", "fallback-title.md"),
"Fallback Title"
);
}
#[test]
fn test_extract_title_empty_fm_falls_back_to_h1() {
assert_eq!(extract_title(Some(""), "# From H1\n", "empty-h1.md"), "From H1");
assert_eq!(
extract_title(Some(""), "# From H1\n", "empty-h1.md"),
"From H1"
);
}
#[test]
fn test_extract_title_empty_fm_no_h1_falls_back_to_filename() {
assert_eq!(extract_title(Some(""), "No heading here.", "empty-h1.md"), "Empty H1");
assert_eq!(
extract_title(Some(""), "No heading here.", "empty-h1.md"),
"Empty H1"
);
}
// --- extract_snippet tests ---

View File

@@ -11,8 +11,6 @@ const makeEntry = (overrides: Partial<VaultEntry> = {}): VaultEntry => ({
belongsTo: [],
relatedTo: [],
status: null,
owner: null,
cadence: null,
archived: false,
trashed: false,
trashedAt: null,
@@ -157,7 +155,7 @@ describe('buildContextualPrompt', () => {
})
describe('buildContextSnapshot', () => {
const active = makeEntry({ path: '/vault/a.md', title: 'Alpha', isA: 'Project', status: 'active', owner: 'Alice' })
const active = makeEntry({ path: '/vault/a.md', title: 'Alpha', isA: 'Project', status: 'active', properties: { Owner: 'Alice' } })
const entries = [
active,
makeEntry({ path: '/vault/b.md', title: 'Beta', isA: 'Person' }),

View File

@@ -85,7 +85,11 @@ function entryFrontmatter(e: VaultEntry): Record<string, unknown> {
const fm: Record<string, unknown> = {}
if (e.isA) fm.type = e.isA
if (e.status) fm.status = e.status
if (e.owner) fm.owner = e.owner
// Owner and cadence are now stored in properties, not first-class fields
const owner = e.properties?.Owner ?? e.properties?.owner
const cadence = e.properties?.Cadence ?? e.properties?.cadence
if (owner) fm.owner = typeof owner === 'string' ? owner : String(owner)
if (cadence) fm.cadence = typeof cadence === 'string' ? cadence : String(cadence)
if (e.belongsTo.length > 0) fm.belongsTo = e.belongsTo
if (e.relatedTo.length > 0) fm.relatedTo = e.relatedTo
if (Object.keys(e.relationships).length > 0) fm.relationships = e.relationships