From 4c6ee111e87a95a6df66f1c53b7679d65619ef25 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Onur=20=C3=96zkan?= Date: Fri, 17 Jul 2026 10:42:59 +0300 Subject: [PATCH] improve specification versioning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Onur Özkan --- README.md | 7 ++-- SPECIFICATIONS.md | 36 ++++++++++++++----- kaptan-spec/src/lib.rs | 4 +-- kaptan-spec/tests/ui/fail_missing_sidecar.rs | 2 +- .../tests/ui/fail_missing_sidecar.stderr | 6 ++-- kaptan-spec/tests/ui/flight_core_contract.rs | 2 +- .../tests/ui/flight_core_contract.spec.md | 25 +++++++++++++ .../ui/flight_core_contract.v0.1.0.spec.md | 10 ------ 8 files changed, 64 insertions(+), 28 deletions(-) create mode 100644 kaptan-spec/tests/ui/flight_core_contract.spec.md delete mode 100644 kaptan-spec/tests/ui/flight_core_contract.v0.1.0.spec.md diff --git a/README.md b/README.md index 925a65f..e127142 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,10 @@ The repository is currently in infrastructure setup. Formal project specificatio Formal specs should be colocated with the code or board package they govern. -- Implementation-linked specs should use versioned sidecar filenames such as `control_loop.v0.1.0.spec.md` next to the related module or package. +- Implementation-linked specs should use stable sidecar filenames such as `control_loop.spec.md` next to the related module or package. +- Version history should live inside the same spec file as additional spec entries, not in the filename. +- Each appended spec entry should begin with version marker such as `# --- version: 0.1.0 ---`. +- Inside a spec entry, `#` is reserved for version markers and content headings should start at `##`. - Rust items should link to those sidecar specs through `#[spec("...")]`. - Missing linked spec files must fail compilation. @@ -37,6 +40,6 @@ Example: ```rust use kaptan_spec::spec; -#[spec("control_loop.v0.1.0.spec.md")] +#[spec("control_loop.spec.md")] pub struct ControlLoop; ``` diff --git a/SPECIFICATIONS.md b/SPECIFICATIONS.md index 09f1e56..b0f689a 100644 --- a/SPECIFICATIONS.md +++ b/SPECIFICATIONS.md @@ -5,9 +5,9 @@ Formal Kaptan specifications should normally live next to the code item they gov Examples: - `kaptan-runtime/src/control_loop.rs` -- `kaptan-runtime/src/control_loop.v0.1.0.spec.md` +- `kaptan-runtime/src/control_loop.spec.md` - `kaptan-runtime/src/scheduler.rs` -- `kaptan-runtime/src/scheduler.v0.1.0.spec.md` +- `kaptan-runtime/src/scheduler.spec.md` ## Compile-Time Linking @@ -18,7 +18,7 @@ Example: ```rust use kaptan_spec::spec; -#[spec("control_loop.v0.1.0.spec.md")] +#[spec("control_loop.spec.md")] pub struct ControlLoop; ``` @@ -26,7 +26,17 @@ The attribute expands to a compile-time file inclusion guard. If the linked file ## Spec Format -Formal specs are expected to declare these keys in YAML frontmatter: +Formal spec files are append-only records for one governed module or package. + +Each file may contain one or more spec entries. Each entry starts with a version heading, followed by YAML frontmatter and a Markdown body. + +Use this exact heading form for each entry: + +```markdown +# --- version: 0.1.0 --- +``` + +Each spec entry must then declare these keys in YAML frontmatter: - `title` - `status` @@ -47,19 +57,27 @@ Owner entries must use full name and email address in this format: The spec path is the identifier for linkage and traceability. - The code path plus the `#[spec("...")]` reference identifies the governing spec. -- The version is part of the spec filename and therefore part of the spec identity. +- The spec file path identifies the governed module or package. +- Individual spec revisions are identified by the version heading. +- A single spec file can carry multiple revisions for the same governed module. +- New revisions should be appended as new spec entries in the same file instead of creating new filenames. +- Within the body of a spec entry, `#` is reserved for version headings. Spec content should start at `##` and below. ## Template -Use this starter when creating a new colocated spec: +Use this starter when creating a colocated spec entry: ```markdown +# --- version: 0.1.0 --- + --- title: Replace with title -status: in-progress +status: deprecated owners: - Full Name --- -# TODO -``` \ No newline at end of file +## TODO +``` + +When the spec evolves, append another entry in the same shape with a new version heading. \ No newline at end of file diff --git a/kaptan-spec/src/lib.rs b/kaptan-spec/src/lib.rs index 176d869..3869fe3 100644 --- a/kaptan-spec/src/lib.rs +++ b/kaptan-spec/src/lib.rs @@ -20,8 +20,8 @@ fn parse_spec_path(attr: TokenStream) -> Result { ] if name.to_string() == "path" && is_equals(eq) && is_string_literal(path) => { Ok(path.to_string()) } - [] => Err("missing spec path; use #[spec(\"file.v0.1.0.spec.md\")]".into()), - _ => Err("invalid spec attribute; use #[spec(\"file.v0.1.0.spec.md\")]".into()), + [] => Err("missing spec path; use #[spec(\"file.spec.md\")]".into()), + _ => Err("invalid spec attribute; use #[spec(\"file.spec.md\")]".into()), } } diff --git a/kaptan-spec/tests/ui/fail_missing_sidecar.rs b/kaptan-spec/tests/ui/fail_missing_sidecar.rs index df44e06..1cddb67 100644 --- a/kaptan-spec/tests/ui/fail_missing_sidecar.rs +++ b/kaptan-spec/tests/ui/fail_missing_sidecar.rs @@ -1,6 +1,6 @@ use kaptan_spec::spec; -#[spec("fail_missing_sidecar.v0.1.0.spec.md")] +#[spec("fail_missing_sidecar.spec.md")] struct MissingSpec; fn main() { diff --git a/kaptan-spec/tests/ui/fail_missing_sidecar.stderr b/kaptan-spec/tests/ui/fail_missing_sidecar.stderr index 2e244a0..bd7cd1e 100644 --- a/kaptan-spec/tests/ui/fail_missing_sidecar.stderr +++ b/kaptan-spec/tests/ui/fail_missing_sidecar.stderr @@ -1,5 +1,5 @@ -error: couldn't read `$DIR/tests/ui/fail_missing_sidecar.v0.1.0.spec.md`: No such file or directory (os error 2) +error: couldn't read `$DIR/tests/ui/fail_missing_sidecar.spec.md`: No such file or directory (os error 2) --> tests/ui/fail_missing_sidecar.rs:3:1 | -3 | #[spec("fail_missing_sidecar.v0.1.0.spec.md")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +3 | #[spec("fail_missing_sidecar.spec.md")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/kaptan-spec/tests/ui/flight_core_contract.rs b/kaptan-spec/tests/ui/flight_core_contract.rs index 0d95b34..399782f 100644 --- a/kaptan-spec/tests/ui/flight_core_contract.rs +++ b/kaptan-spec/tests/ui/flight_core_contract.rs @@ -1,6 +1,6 @@ use kaptan_spec::spec; -#[spec("flight_core_contract.v0.1.0.spec.md")] +#[spec("flight_core_contract.spec.md")] struct FlightCore; fn main() { diff --git a/kaptan-spec/tests/ui/flight_core_contract.spec.md b/kaptan-spec/tests/ui/flight_core_contract.spec.md new file mode 100644 index 0000000..2b1140e --- /dev/null +++ b/kaptan-spec/tests/ui/flight_core_contract.spec.md @@ -0,0 +1,25 @@ +# --- version: 0.1.0 --- + +--- +title: Flight core contract +status: in-progress +owners: + - Flight Systems +--- + +## Contract + +Initial control contract. + +# --- version: 0.2.0 --- + +--- +title: Flight core contract +status: implemented +owners: + - Flight Systems +--- + +## Contract + +Revised control contract. \ No newline at end of file diff --git a/kaptan-spec/tests/ui/flight_core_contract.v0.1.0.spec.md b/kaptan-spec/tests/ui/flight_core_contract.v0.1.0.spec.md deleted file mode 100644 index e0d3901..0000000 --- a/kaptan-spec/tests/ui/flight_core_contract.v0.1.0.spec.md +++ /dev/null @@ -1,10 +0,0 @@ ---- -title: Flight core contract -status: in-progress -owners: - - Test Name ---- - -# Summary - -Minimal spec for compile-time linkage testing. \ No newline at end of file