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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions blog/BattlesnakeMinimax/Minimax in Battlesnake.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ image: ../diagrams/19.png
tags:
- battlesnake
- Minimax
track: battlesnake
---

# Minimax in Battlesnake
Expand Down
1 change: 1 addition & 0 deletions blog/arena-stress-testing/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ tags:
- battlesnake
- rust
- infrastructure
track: battlesnake
atproto_uri: at://did:plc:bg2gnrjiv6htfynausierbm2/site.standard.document/arena-stress-testing
atproto_pub_cid: bafyreibn466glibcavfowito3sot5hosargmk4jmhg2ldx2lcw3ifcyxti
---
Expand Down
1 change: 1 addition & 0 deletions blog/battlesnake-in-2023/Battlesnake-in-2023.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ date: 2023-03-07
color: blue
tags:
- battlesnake
track: battlesnake
---

# Battlesnake In 2023
Expand Down
1 change: 1 addition & 0 deletions blog/battlesnake-in-2026/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ date: 2026-01-10
tags:
- battlesnake
- rust
track: battlesnake
atproto_uri: at://did:plc:bg2gnrjiv6htfynausierbm2/site.standard.document/battlesnake-in-2026
atproto_pub_cid: bafyreibn466glibcavfowito3sot5hosargmk4jmhg2ldx2lcw3ifcyxti
---
Expand Down
50 changes: 50 additions & 0 deletions posts/src/blog.rs
Original file line number Diff line number Diff line change
Expand Up @@ -223,10 +223,23 @@ pub struct PostMarkdown {
pub ast: MarkdownAst,
}

/// Which accountability track a published artifact counts toward on the
/// `/pace` dashboard. Set via the `track` frontmatter field; defaults to
/// `Other` so off-topic posts count as the floor track without manual tagging.
#[derive(Deserialize, Serialize, Debug, Clone, Copy, PartialEq, Eq, Default)]
#[serde(rename_all = "lowercase")]
pub enum Track {
Battlesnake,
#[default]
Other,
}

#[derive(Deserialize, Serialize, Debug, Clone, PartialEq)]
pub struct BlogFrontMatter {
pub title: String,
pub date: NaiveDate,
#[serde(default)]
pub track: Track,
#[serde(default = "default_is_newsletter")]
pub is_newsletter: bool,
pub bsky_url: Option<String>,
Expand Down Expand Up @@ -340,6 +353,7 @@ mod test {
let meta = BlogFrontMatter {
title: "Sample Post".to_string(),
date: NaiveDate::default(),
track: Track::default(),
is_newsletter: false,
bsky_url: None,
newsletter_send_at: None,
Expand Down Expand Up @@ -380,6 +394,7 @@ mod test {
frontmatter: BlogFrontMatter {
title: "T".to_string(),
date: NaiveDate::default(),
track: Track::default(),
is_newsletter,
bsky_url: None,
newsletter_send_at: None,
Expand Down Expand Up @@ -419,5 +434,40 @@ mod test {
let fm: BlogFrontMatter = serde_yaml::from_str(yaml).unwrap();
assert_eq!(fm.publication, "blog");
assert!(fm.atproto_uri.is_none());
assert_eq!(fm.track, Track::Other);
}

#[test]
fn track_defaults_to_other_when_field_missing() {
let yaml = "title: T\ndate: 2026-05-01";
let fm: BlogFrontMatter = serde_yaml::from_str(yaml).unwrap();
assert_eq!(fm.track, Track::Other);
}

#[test]
fn track_parses_battlesnake() {
let yaml = "title: T\ndate: 2026-05-01\ntrack: battlesnake";
let fm: BlogFrontMatter = serde_yaml::from_str(yaml).unwrap();
assert_eq!(fm.track, Track::Battlesnake);
}

#[test]
fn track_rejects_unknown_value() {
let yaml = "title: T\ndate: 2026-05-01\ntrack: invalid";
let err = serde_yaml::from_str::<BlogFrontMatter>(yaml).unwrap_err();
let msg = err.to_string();
assert!(
msg.contains("track") || msg.contains("variant"),
"error should mention the bad field; got: {msg}"
);
}

#[test]
fn blog_load_from_static_dir() {
let blog = BlogPosts::from_static_dir().unwrap();
assert!(
!blog.posts.is_empty(),
"Should have at least one blog post loaded from the blog/ directory"
);
}
}
44 changes: 43 additions & 1 deletion posts/src/notes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use serde::{Deserialize, Serialize};
use crate::{MarkdownAst, Post};

use super::{
blog::ValidateMarkdown,
blog::{Track, ValidateMarkdown},
date::{ByRecency, PostedOn},
title::Title,
};
Expand All @@ -32,6 +32,8 @@ pub struct FrontMatter {
pub bsky_url: Option<String>,
#[serde(default)]
pub tags: Vec<String>,
#[serde(default)]
pub track: Track,
}

impl PostedOn for FrontMatter {
Expand Down Expand Up @@ -150,6 +152,46 @@ slug: test-note
assert_eq!(fm.slug, "test-note");
assert_eq!(fm.bsky_url, None);
assert!(fm.tags.is_empty(), "tags should default to empty");
assert_eq!(fm.track, Track::Other);
}

#[test]
fn track_defaults_to_other_when_field_missing() {
let yaml = r"
title: Test Note
date: 2026-03-01
slug: test-note
";
let fm: FrontMatter = serde_yaml::from_str(yaml).unwrap();
assert_eq!(fm.track, Track::Other);
}

#[test]
fn track_parses_battlesnake() {
let yaml = r"
title: Test Note
date: 2026-03-01
slug: test-note
track: battlesnake
";
let fm: FrontMatter = serde_yaml::from_str(yaml).unwrap();
assert_eq!(fm.track, Track::Battlesnake);
}

#[test]
fn track_rejects_unknown_value() {
let yaml = r"
title: Test Note
date: 2026-03-01
slug: test-note
track: invalid
";
let err = serde_yaml::from_str::<FrontMatter>(yaml).unwrap_err();
let msg = err.to_string();
assert!(
msg.contains("track") || msg.contains("variant"),
"error should mention the bad field; got: {msg}"
);
}

#[test]
Expand Down
2 changes: 2 additions & 0 deletions server/src/commands/standard_site.rs
Original file line number Diff line number Diff line change
Expand Up @@ -589,6 +589,7 @@ fn write_back(post_path: &Path, content: &str) -> cja::Result<()> {
mod tests {
use super::*;
use chrono::NaiveDate;
use posts::blog::Track;
use std::io::Write;

fn sample_publication() -> PublicationConfig {
Expand All @@ -609,6 +610,7 @@ mod tests {
BlogFrontMatter {
title: "T".to_string(),
date: NaiveDate::default(),
track: Track::default(),
is_newsletter: false,
bsky_url: None,
newsletter_send_at: None,
Expand Down
3 changes: 2 additions & 1 deletion server/src/http_server/admin/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,8 @@ pub(crate) async fn dashboard(
a href="/admin/threads" class="text-blue-500 hover:underline mr-4" { "Agentic Threads →" }
a href="/admin/tool-suggestions" class="text-blue-500 hover:underline mr-4" { "Tool Suggestions →" }
a href="/admin/persona" class="text-blue-500 hover:underline mr-4" { "Persona →" }
a href="/admin/memories" class="text-blue-500 hover:underline" { "Memory Blocks →" }
a href="/admin/memories" class="text-blue-500 hover:underline mr-4" { "Memory Blocks →" }
a href="/pace" class="text-blue-500 hover:underline" { "Pace Dashboard →" }
}

h3 class="py-2 text-lg" { "Last Refresh Ats" }
Expand Down
1 change: 1 addition & 0 deletions server/src/http_server/pages/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ pub mod legal;
pub mod login;
pub mod notes;
pub mod og;
pub mod pace;
pub mod podcast;
pub mod projects;
pub mod videos;
Expand Down
Loading
Loading