From 0c1b8f0c32be8a042420aee5f0766c048b1ba6e6 Mon Sep 17 00:00:00 2001 From: "ptr727-codegen[bot]" <275599072+ptr727-codegen[bot]@users.noreply.github.com> Date: Mon, 18 May 2026 03:01:46 +0000 Subject: [PATCH 01/32] Update codegen files --- CodeGen/CodeGen.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CodeGen/CodeGen.cs b/CodeGen/CodeGen.cs index a4d051e2..22a57664 100644 --- a/CodeGen/CodeGen.cs +++ b/CodeGen/CodeGen.cs @@ -8,7 +8,7 @@ internal static class CodeGen internal static void Quote() { - const string dateTime = "2026-04-30T03:07:13.4355622Z"; + const string dateTime = "2026-05-18T03:01:38.0586119Z"; Console.WriteLine($"{dateTime} : {QuoteOfTheDay}"); Log.Logger.Information("Quote of the Day: {DateTime} : {Quote}", dateTime, QuoteOfTheDay); } From 1ba1399ee49bfe44bdabac6ed416dc81fa22db5f Mon Sep 17 00:00:00 2001 From: "ptr727-codegen[bot]" <275599072+ptr727-codegen[bot]@users.noreply.github.com> Date: Mon, 25 May 2026 03:02:15 +0000 Subject: [PATCH 02/32] Update codegen files --- CodeGen/CodeGen.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CodeGen/CodeGen.cs b/CodeGen/CodeGen.cs index 22a57664..106831f5 100644 --- a/CodeGen/CodeGen.cs +++ b/CodeGen/CodeGen.cs @@ -8,7 +8,7 @@ internal static class CodeGen internal static void Quote() { - const string dateTime = "2026-05-18T03:01:38.0586119Z"; + const string dateTime = "2026-05-25T03:02:08.3686012Z"; Console.WriteLine($"{dateTime} : {QuoteOfTheDay}"); Log.Logger.Information("Quote of the Day: {DateTime} : {Quote}", dateTime, QuoteOfTheDay); } From 1d99e74df880e036c2671fbf278ff93440d4bf89 Mon Sep 17 00:00:00 2001 From: "ptr727-codegen[bot]" <275599072+ptr727-codegen[bot]@users.noreply.github.com> Date: Mon, 1 Jun 2026 03:02:47 +0000 Subject: [PATCH 03/32] Update codegen files --- CodeGen/CodeGen.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CodeGen/CodeGen.cs b/CodeGen/CodeGen.cs index 106831f5..05be9920 100644 --- a/CodeGen/CodeGen.cs +++ b/CodeGen/CodeGen.cs @@ -8,7 +8,7 @@ internal static class CodeGen internal static void Quote() { - const string dateTime = "2026-05-25T03:02:08.3686012Z"; + const string dateTime = "2026-06-01T03:02:39.3189096Z"; Console.WriteLine($"{dateTime} : {QuoteOfTheDay}"); Log.Logger.Information("Quote of the Day: {DateTime} : {Quote}", dateTime, QuoteOfTheDay); } From c0869455c380e79a5e2e3f8c10cf510194a43543 Mon Sep 17 00:00:00 2001 From: "ptr727-codegen[bot]" <275599072+ptr727-codegen[bot]@users.noreply.github.com> Date: Wed, 3 Jun 2026 23:45:06 +0000 Subject: [PATCH 04/32] Update codegen files --- CodeGen/CodeGen.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CodeGen/CodeGen.cs b/CodeGen/CodeGen.cs index 05be9920..399969b4 100644 --- a/CodeGen/CodeGen.cs +++ b/CodeGen/CodeGen.cs @@ -8,7 +8,7 @@ internal static class CodeGen internal static void Quote() { - const string dateTime = "2026-06-01T03:02:39.3189096Z"; + const string dateTime = "2026-06-03T23:44:33Z"; Console.WriteLine($"{dateTime} : {QuoteOfTheDay}"); Log.Logger.Information("Quote of the Day: {DateTime} : {Quote}", dateTime, QuoteOfTheDay); } From 810cd4bb02f0ce7db376f03b3996ef9d81b7f24d Mon Sep 17 00:00:00 2001 From: "ptr727-codegen[bot]" <275599072+ptr727-codegen[bot]@users.noreply.github.com> Date: Thu, 4 Jun 2026 05:46:31 +0000 Subject: [PATCH 05/32] Update codegen files --- CodeGen/CodeGen.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CodeGen/CodeGen.cs b/CodeGen/CodeGen.cs index 399969b4..55f7fbb7 100644 --- a/CodeGen/CodeGen.cs +++ b/CodeGen/CodeGen.cs @@ -8,7 +8,7 @@ internal static class CodeGen internal static void Quote() { - const string dateTime = "2026-06-03T23:44:33Z"; + const string dateTime = "2026-06-04T05:46:01Z"; Console.WriteLine($"{dateTime} : {QuoteOfTheDay}"); Log.Logger.Information("Quote of the Day: {DateTime} : {Quote}", dateTime, QuoteOfTheDay); } From 10c83d1313f57856980524924f5104e0768e8e95 Mon Sep 17 00:00:00 2001 From: "ptr727-codegen[bot]" <275599072+ptr727-codegen[bot]@users.noreply.github.com> Date: Fri, 5 Jun 2026 05:42:13 +0000 Subject: [PATCH 06/32] Update codegen files --- CodeGen/CodeGen.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CodeGen/CodeGen.cs b/CodeGen/CodeGen.cs index 55f7fbb7..95736e39 100644 --- a/CodeGen/CodeGen.cs +++ b/CodeGen/CodeGen.cs @@ -8,7 +8,7 @@ internal static class CodeGen internal static void Quote() { - const string dateTime = "2026-06-04T05:46:01Z"; + const string dateTime = "2026-06-05T05:41:45Z"; Console.WriteLine($"{dateTime} : {QuoteOfTheDay}"); Log.Logger.Information("Quote of the Day: {DateTime} : {Quote}", dateTime, QuoteOfTheDay); } From 55c2049d16339e3211e149a30618430ee9f4d448 Mon Sep 17 00:00:00 2001 From: "ptr727-codegen[bot]" <275599072+ptr727-codegen[bot]@users.noreply.github.com> Date: Sat, 6 Jun 2026 05:27:12 +0000 Subject: [PATCH 07/32] Update codegen files --- CodeGen/CodeGen.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CodeGen/CodeGen.cs b/CodeGen/CodeGen.cs index 95736e39..54e066a1 100644 --- a/CodeGen/CodeGen.cs +++ b/CodeGen/CodeGen.cs @@ -8,7 +8,7 @@ internal static class CodeGen internal static void Quote() { - const string dateTime = "2026-06-05T05:41:45Z"; + const string dateTime = "2026-06-06T05:26:39Z"; Console.WriteLine($"{dateTime} : {QuoteOfTheDay}"); Log.Logger.Information("Quote of the Day: {DateTime} : {Quote}", dateTime, QuoteOfTheDay); } From 26971a57ef420ae8197f7853c05587c582f82f5a Mon Sep 17 00:00:00 2001 From: "ptr727-codegen[bot]" <275599072+ptr727-codegen[bot]@users.noreply.github.com> Date: Sun, 7 Jun 2026 05:41:46 +0000 Subject: [PATCH 08/32] Update codegen files --- CodeGen/CodeGen.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CodeGen/CodeGen.cs b/CodeGen/CodeGen.cs index 54e066a1..41440f80 100644 --- a/CodeGen/CodeGen.cs +++ b/CodeGen/CodeGen.cs @@ -8,7 +8,7 @@ internal static class CodeGen internal static void Quote() { - const string dateTime = "2026-06-06T05:26:39Z"; + const string dateTime = "2026-06-07T05:41:13Z"; Console.WriteLine($"{dateTime} : {QuoteOfTheDay}"); Log.Logger.Information("Quote of the Day: {DateTime} : {Quote}", dateTime, QuoteOfTheDay); } From 0c7806694a21ce42f898af9d54b8b97ab350f441 Mon Sep 17 00:00:00 2001 From: "ptr727-codegen[bot]" <275599072+ptr727-codegen[bot]@users.noreply.github.com> Date: Mon, 8 Jun 2026 05:46:21 +0000 Subject: [PATCH 09/32] Update codegen files --- CodeGen/CodeGen.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CodeGen/CodeGen.cs b/CodeGen/CodeGen.cs index 41440f80..b0a4e3b5 100644 --- a/CodeGen/CodeGen.cs +++ b/CodeGen/CodeGen.cs @@ -8,7 +8,7 @@ internal static class CodeGen internal static void Quote() { - const string dateTime = "2026-06-07T05:41:13Z"; + const string dateTime = "2026-06-08T05:45:52Z"; Console.WriteLine($"{dateTime} : {QuoteOfTheDay}"); Log.Logger.Information("Quote of the Day: {DateTime} : {Quote}", dateTime, QuoteOfTheDay); } From f6b767271c18536ac94f39ccedb69a949b6c6935 Mon Sep 17 00:00:00 2001 From: "ptr727-codegen[bot]" <275599072+ptr727-codegen[bot]@users.noreply.github.com> Date: Tue, 9 Jun 2026 05:32:43 +0000 Subject: [PATCH 10/32] Update codegen files --- CodeGen/CodeGen.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CodeGen/CodeGen.cs b/CodeGen/CodeGen.cs index b0a4e3b5..320f75d9 100644 --- a/CodeGen/CodeGen.cs +++ b/CodeGen/CodeGen.cs @@ -8,7 +8,7 @@ internal static class CodeGen internal static void Quote() { - const string dateTime = "2026-06-08T05:45:52Z"; + const string dateTime = "2026-06-09T05:32:04Z"; Console.WriteLine($"{dateTime} : {QuoteOfTheDay}"); Log.Logger.Information("Quote of the Day: {DateTime} : {Quote}", dateTime, QuoteOfTheDay); } From 8f778ca62b3a9e813e3ecf505385ecdc0a4a2492 Mon Sep 17 00:00:00 2001 From: "ptr727-codegen[bot]" <275599072+ptr727-codegen[bot]@users.noreply.github.com> Date: Wed, 10 Jun 2026 05:42:21 +0000 Subject: [PATCH 11/32] Update codegen files --- CodeGen/CodeGen.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CodeGen/CodeGen.cs b/CodeGen/CodeGen.cs index 320f75d9..19bde44a 100644 --- a/CodeGen/CodeGen.cs +++ b/CodeGen/CodeGen.cs @@ -8,7 +8,7 @@ internal static class CodeGen internal static void Quote() { - const string dateTime = "2026-06-09T05:32:04Z"; + const string dateTime = "2026-06-10T05:41:45Z"; Console.WriteLine($"{dateTime} : {QuoteOfTheDay}"); Log.Logger.Information("Quote of the Day: {DateTime} : {Quote}", dateTime, QuoteOfTheDay); } From 554ab91533a29a2b3470f96a0730278cb852d655 Mon Sep 17 00:00:00 2001 From: "ptr727-codegen[bot]" <275599072+ptr727-codegen[bot]@users.noreply.github.com> Date: Thu, 11 Jun 2026 05:45:51 +0000 Subject: [PATCH 12/32] Update codegen files --- CodeGen/CodeGen.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CodeGen/CodeGen.cs b/CodeGen/CodeGen.cs index 19bde44a..fc6d5c07 100644 --- a/CodeGen/CodeGen.cs +++ b/CodeGen/CodeGen.cs @@ -8,7 +8,7 @@ internal static class CodeGen internal static void Quote() { - const string dateTime = "2026-06-10T05:41:45Z"; + const string dateTime = "2026-06-11T05:45:14Z"; Console.WriteLine($"{dateTime} : {QuoteOfTheDay}"); Log.Logger.Information("Quote of the Day: {DateTime} : {Quote}", dateTime, QuoteOfTheDay); } From 4f440fc283a24116004c6103265b75e20aa95e22 Mon Sep 17 00:00:00 2001 From: "ptr727-codegen[bot]" <275599072+ptr727-codegen[bot]@users.noreply.github.com> Date: Fri, 12 Jun 2026 05:45:12 +0000 Subject: [PATCH 13/32] Update codegen files --- CodeGen/CodeGen.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CodeGen/CodeGen.cs b/CodeGen/CodeGen.cs index fc6d5c07..1a66e098 100644 --- a/CodeGen/CodeGen.cs +++ b/CodeGen/CodeGen.cs @@ -8,7 +8,7 @@ internal static class CodeGen internal static void Quote() { - const string dateTime = "2026-06-11T05:45:14Z"; + const string dateTime = "2026-06-12T05:44:37Z"; Console.WriteLine($"{dateTime} : {QuoteOfTheDay}"); Log.Logger.Information("Quote of the Day: {DateTime} : {Quote}", dateTime, QuoteOfTheDay); } From 458f167570fee32d38c687667199e505a96af275 Mon Sep 17 00:00:00 2001 From: "ptr727-codegen[bot]" <275599072+ptr727-codegen[bot]@users.noreply.github.com> Date: Sun, 14 Jun 2026 05:44:55 +0000 Subject: [PATCH 14/32] Update codegen files --- CodeGen/CodeGen.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CodeGen/CodeGen.cs b/CodeGen/CodeGen.cs index 1a66e098..52e42b23 100644 --- a/CodeGen/CodeGen.cs +++ b/CodeGen/CodeGen.cs @@ -8,7 +8,7 @@ internal static class CodeGen internal static void Quote() { - const string dateTime = "2026-06-12T05:44:37Z"; + const string dateTime = "2026-06-14T05:44:18Z"; Console.WriteLine($"{dateTime} : {QuoteOfTheDay}"); Log.Logger.Information("Quote of the Day: {DateTime} : {Quote}", dateTime, QuoteOfTheDay); } From 6aa3bb5bcf4658eb57c9f7f1b5b87e8a5eda5874 Mon Sep 17 00:00:00 2001 From: "ptr727-codegen[bot]" <275599072+ptr727-codegen[bot]@users.noreply.github.com> Date: Mon, 15 Jun 2026 06:00:21 +0000 Subject: [PATCH 15/32] Update codegen files --- CodeGen/CodeGen.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CodeGen/CodeGen.cs b/CodeGen/CodeGen.cs index 52e42b23..18ee6ba5 100644 --- a/CodeGen/CodeGen.cs +++ b/CodeGen/CodeGen.cs @@ -8,7 +8,7 @@ internal static class CodeGen internal static void Quote() { - const string dateTime = "2026-06-14T05:44:18Z"; + const string dateTime = "2026-06-15T05:59:38Z"; Console.WriteLine($"{dateTime} : {QuoteOfTheDay}"); Log.Logger.Information("Quote of the Day: {DateTime} : {Quote}", dateTime, QuoteOfTheDay); } From 8dca8d34f4edf87e3471d58656ecc9033bceaba3 Mon Sep 17 00:00:00 2001 From: "ptr727-codegen[bot]" <275599072+ptr727-codegen[bot]@users.noreply.github.com> Date: Tue, 16 Jun 2026 06:02:05 +0000 Subject: [PATCH 16/32] Update codegen files --- CodeGen/CodeGen.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CodeGen/CodeGen.cs b/CodeGen/CodeGen.cs index 18ee6ba5..2880165e 100644 --- a/CodeGen/CodeGen.cs +++ b/CodeGen/CodeGen.cs @@ -8,7 +8,7 @@ internal static class CodeGen internal static void Quote() { - const string dateTime = "2026-06-15T05:59:38Z"; + const string dateTime = "2026-06-16T06:01:23Z"; Console.WriteLine($"{dateTime} : {QuoteOfTheDay}"); Log.Logger.Information("Quote of the Day: {DateTime} : {Quote}", dateTime, QuoteOfTheDay); } From c4b0d1957c397f5c4949c5949dea7c776487159a Mon Sep 17 00:00:00 2001 From: "ptr727-codegen[bot]" <275599072+ptr727-codegen[bot]@users.noreply.github.com> Date: Wed, 17 Jun 2026 05:51:05 +0000 Subject: [PATCH 17/32] Update codegen files --- CodeGen/CodeGen.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CodeGen/CodeGen.cs b/CodeGen/CodeGen.cs index 2880165e..265c7c68 100644 --- a/CodeGen/CodeGen.cs +++ b/CodeGen/CodeGen.cs @@ -8,7 +8,7 @@ internal static class CodeGen internal static void Quote() { - const string dateTime = "2026-06-16T06:01:23Z"; + const string dateTime = "2026-06-17T05:50:25Z"; Console.WriteLine($"{dateTime} : {QuoteOfTheDay}"); Log.Logger.Information("Quote of the Day: {DateTime} : {Quote}", dateTime, QuoteOfTheDay); } From 9bdd14635a5e91b0bde2f1284983bf7d6dc500bc Mon Sep 17 00:00:00 2001 From: "ptr727-codegen[bot]" <275599072+ptr727-codegen[bot]@users.noreply.github.com> Date: Thu, 18 Jun 2026 05:47:20 +0000 Subject: [PATCH 18/32] Update codegen files --- CodeGen/CodeGen.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CodeGen/CodeGen.cs b/CodeGen/CodeGen.cs index 265c7c68..6c98a229 100644 --- a/CodeGen/CodeGen.cs +++ b/CodeGen/CodeGen.cs @@ -8,7 +8,7 @@ internal static class CodeGen internal static void Quote() { - const string dateTime = "2026-06-17T05:50:25Z"; + const string dateTime = "2026-06-18T05:46:39Z"; Console.WriteLine($"{dateTime} : {QuoteOfTheDay}"); Log.Logger.Information("Quote of the Day: {DateTime} : {Quote}", dateTime, QuoteOfTheDay); } From 6f079792be3608a039bfa73d615875f7a8505f2c Mon Sep 17 00:00:00 2001 From: "ptr727-codegen[bot]" <275599072+ptr727-codegen[bot]@users.noreply.github.com> Date: Fri, 19 Jun 2026 05:54:05 +0000 Subject: [PATCH 19/32] Update codegen files --- CodeGen/CodeGen.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CodeGen/CodeGen.cs b/CodeGen/CodeGen.cs index 6c98a229..837a29ee 100644 --- a/CodeGen/CodeGen.cs +++ b/CodeGen/CodeGen.cs @@ -8,7 +8,7 @@ internal static class CodeGen internal static void Quote() { - const string dateTime = "2026-06-18T05:46:39Z"; + const string dateTime = "2026-06-19T05:53:27Z"; Console.WriteLine($"{dateTime} : {QuoteOfTheDay}"); Log.Logger.Information("Quote of the Day: {DateTime} : {Quote}", dateTime, QuoteOfTheDay); } From a5b5819eb4378e6b1fb29f073f42e4745b9bc133 Mon Sep 17 00:00:00 2001 From: "ptr727-codegen[bot]" <275599072+ptr727-codegen[bot]@users.noreply.github.com> Date: Sat, 20 Jun 2026 05:39:47 +0000 Subject: [PATCH 20/32] Update codegen files --- CodeGen/CodeGen.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CodeGen/CodeGen.cs b/CodeGen/CodeGen.cs index 837a29ee..080d442a 100644 --- a/CodeGen/CodeGen.cs +++ b/CodeGen/CodeGen.cs @@ -8,7 +8,7 @@ internal static class CodeGen internal static void Quote() { - const string dateTime = "2026-06-19T05:53:27Z"; + const string dateTime = "2026-06-20T05:39:12Z"; Console.WriteLine($"{dateTime} : {QuoteOfTheDay}"); Log.Logger.Information("Quote of the Day: {DateTime} : {Quote}", dateTime, QuoteOfTheDay); } From b18ede0e7aa6ca72907112c911c112cbe3a6d517 Mon Sep 17 00:00:00 2001 From: "ptr727-codegen[bot]" <275599072+ptr727-codegen[bot]@users.noreply.github.com> Date: Sun, 21 Jun 2026 05:47:34 +0000 Subject: [PATCH 21/32] Update codegen files --- CodeGen/CodeGen.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CodeGen/CodeGen.cs b/CodeGen/CodeGen.cs index 080d442a..05c06992 100644 --- a/CodeGen/CodeGen.cs +++ b/CodeGen/CodeGen.cs @@ -8,7 +8,7 @@ internal static class CodeGen internal static void Quote() { - const string dateTime = "2026-06-20T05:39:12Z"; + const string dateTime = "2026-06-21T05:47:00Z"; Console.WriteLine($"{dateTime} : {QuoteOfTheDay}"); Log.Logger.Information("Quote of the Day: {DateTime} : {Quote}", dateTime, QuoteOfTheDay); } From 8363822c1070c606b92a0502cafa32c385f327c1 Mon Sep 17 00:00:00 2001 From: "ptr727-codegen[bot]" <275599072+ptr727-codegen[bot]@users.noreply.github.com> Date: Mon, 22 Jun 2026 06:02:30 +0000 Subject: [PATCH 22/32] Update codegen files --- CodeGen/CodeGen.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CodeGen/CodeGen.cs b/CodeGen/CodeGen.cs index 05c06992..89aaa922 100644 --- a/CodeGen/CodeGen.cs +++ b/CodeGen/CodeGen.cs @@ -8,7 +8,7 @@ internal static class CodeGen internal static void Quote() { - const string dateTime = "2026-06-21T05:47:00Z"; + const string dateTime = "2026-06-22T06:01:35Z"; Console.WriteLine($"{dateTime} : {QuoteOfTheDay}"); Log.Logger.Information("Quote of the Day: {DateTime} : {Quote}", dateTime, QuoteOfTheDay); } From 5c09edd584359f757cbeae394199c3fdbc6c1435 Mon Sep 17 00:00:00 2001 From: "ptr727-codegen[bot]" <275599072+ptr727-codegen[bot]@users.noreply.github.com> Date: Tue, 23 Jun 2026 05:31:05 +0000 Subject: [PATCH 23/32] Update codegen files --- CodeGen/CodeGen.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CodeGen/CodeGen.cs b/CodeGen/CodeGen.cs index 89aaa922..fac1c52b 100644 --- a/CodeGen/CodeGen.cs +++ b/CodeGen/CodeGen.cs @@ -8,7 +8,7 @@ internal static class CodeGen internal static void Quote() { - const string dateTime = "2026-06-22T06:01:35Z"; + const string dateTime = "2026-06-23T05:30:24Z"; Console.WriteLine($"{dateTime} : {QuoteOfTheDay}"); Log.Logger.Information("Quote of the Day: {DateTime} : {Quote}", dateTime, QuoteOfTheDay); } From 048a442f293504fe9b75d135bbac93910e4e54b8 Mon Sep 17 00:00:00 2001 From: Pieter Viljoen Date: Sat, 1 Aug 2026 11:23:09 -0700 Subject: [PATCH 24/32] Refresh the PhotoCleaner audit report and driftNotes (#508) The committed `reports/photocleaner/audit.md` was dated 2026-07-23 and predated the release pipeline, so it still listed both branch rulesets as missing and the Dockerfile as dead weight. All of that landed, and release `1.0.9` shipped that same day. Re-audited against `main@15b9b5b`. **Run stamp:** `audit run 2026-08-01T15:30:19Z | hub 6501479` ## What the re-audit found Everything the old snapshot called a defect is fixed. The remaining findings are a different set, created mostly by **this hub advancing** rather than by the repo regressing: | | | | --- | --- | | **defect** | The agent instruction set predates the router split: `GOVERNANCE.md` absent, `AGENTS.md` still the pre-split single file, so neither verbatim region compares and all ten sections read as undeclared | | **defect** | README intro 150 chars against the 100-char cap, with the Docker Hub short description no longer mirroring it | | **drift** | `.markdownlint-cli2.jsonc` and `repo-config/configure.sh` both match a past hub revision | | **drift** | `build-release-task.yml` has no `validate-release` job, though that repo's own `WORKFLOW.md` names it in D2.2 and in scenarios S1, S4, and S10, and its `github-release` body matches no hub revision | `develop` and `main` report identical findings, so the commit-count gap remains the benign promotion-merge ancestry artifact. ## Convergence Six PRs are open against PhotoCleaner `develop`, one per drift class per AUDIT.md section 10, each with a Copilot review on its head SHA, left for the maintainer to merge. They are listed in the report. ## Three hub-side defects this surfaced Raised per AUDIT.md section 9 rather than resolved here, since each re-vendors fleet-wide and deserves its own change: 1. **The hub's own `.github/copilot-instructions.md` describes the pre-split file.** `Reviewing Carried Fleet Content` says "Most of `AGENTS.md` is universal fleet law: every section that states a rule, as opposed to the two that describe this repository's own directory tree and devcontainer". After the split those sections are in `GOVERNANCE.md`, and `AGENTS.md` carries exactly two verbatim sections and no repo-specific ones. PhotoCleaner had to adapt the text on the way down, and every other repo carrying it inherits the stale description. 2. **`CODESTYLE.md` contradicts `.markdownlint-cli2.jsonc` on MD033.** The prose still says "HTML elements are flagged" after the config gained `allowed_elements: ["details", "summary"]`. This is the "when you change a behavior, search for prose that asserts the old one" rule, unswept. 3. **`spec/readme-structure.md` assumes a public repository.** PhotoCleaner is private, so shields.io cannot read its GitHub release, build, or commit data and every GitHub-sourced badge renders broken. Build Status and Releases state no behavior for that case. Plus two softer ones: the `HISTORY.md` mirror rule lives only in hub-only `spec/readme-structure.md`, so a downstream repo cannot point at the rule it is measured against; and `WORKFLOW.md` D2.2's "skipped on smoke" is ambiguous enough that a Copilot review read it as the GitHub job status and proposed a change that would have coupled `github-release` to smoke through its `needs`. ## driftNotes Dropped the stale claim that the report predates the release wiring, dropped the cross-repo comparison (the "Carried files carry no coordination references" rule bans a sibling repo named as an illustrative example, and a registry entry is the same shape of problem), and recorded that the repo is private while its Docker image is public, so the declared `github-release` channel is not pullable by a consumer. ## Verification - `spec/validate.py`: "Spec validation OK: 21 cataloged, 0 backlog repos classify cleanly." - `scripts/repo_gate.py`: eol 0 issues, sha-pin 0 issues. - `scripts/prose_lint.py` on the report: exit 0. - `markdownlint-cli2` on the report: 0 issues. --------- Co-authored-by: Claude Opus 5 (1M context) --- registry/repos.json | 2 +- reports/photocleaner/audit.md | 67 ++++++++++++++++++++++++----------- 2 files changed, 47 insertions(+), 22 deletions(-) diff --git a/registry/repos.json b/registry/repos.json index ac81a910..4f467859 100644 --- a/registry/repos.json +++ b/registry/repos.json @@ -250,7 +250,7 @@ "requiredSecrets": ["DOCKER_HUB_USERNAME", "DOCKER_HUB_ACCESS_TOKEN", "CODECOV_TOKEN"], "consumerModel": "pull", "releaseTrigger": "two-phase", - "driftNotes": ["Mirrors PlexCleaner's publish shape minus the python subtree: multi-arch Docker (linux/amd64,linux/arm64 on main) pushed to Docker Hub via the static DOCKER_HUB_USERNAME/DOCKER_HUB_ACCESS_TOKEN secret, plus a github-release attaching the multi-arch executables as a 7z. Release is two-phase (workflow_dispatch + weekly Mon 02:00 schedule).", "Fully onboarded 2026-07 (rulesets, repo-config/, version.json, WORKFLOW.md, AUDIT.md, dependabot.yml, and the release pipeline all live). The reports/photocleaner/audit.md snapshot predates the docker/release wiring."] + "driftNotes": ["Multi-arch Docker (linux/amd64,linux/arm64 on main) pushed to Docker Hub via the static DOCKER_HUB_USERNAME/DOCKER_HUB_ACCESS_TOKEN secret, plus a github-release attaching the multi-arch executables as a 7z. Release is two-phase (workflow_dispatch + weekly Mon 02:00 schedule). First release 1.0.9 published 2026-07-23.", "Baseline onboarding completed 2026-07 (rulesets, repo-config/, version.json, WORKFLOW.md, AUDIT.md, dependabot.yml, and the release pipeline all live). Not conformance-complete: see reports/photocleaner/audit.md for the open defects.", "Private for now by maintainer decision, going public once the conformance work settles, since public serves prospective users and lowers the GitHub bill. Until that flip the declared github-release channel is not consumer-pullable and shields.io cannot read the repo, so README.md carries Docker Hub shields only and gains the GitHub build and release shields when it goes public."] }, { "name": "MediaTools", diff --git a/reports/photocleaner/audit.md b/reports/photocleaner/audit.md index b5a5f36f..7b8ebaa1 100644 --- a/reports/photocleaner/audit.md +++ b/reports/photocleaner/audit.md @@ -1,44 +1,69 @@ # Audit: PhotoCleaner -- **Audited branch:** main (`3b33b98956190b91b8ed1d3e49e8242545ea523c`) +- **Audited branch:** main (`15b9b5b7411bbba43b8bff8044c4b651355c10a4`) - **Types:** csharp, console, docker (from registry) - **Verdict:** not operational -- **Date:** 2026-07-23 -- **Run stamp:** `audit run 2026-07-23T13:51:20Z | hub 614a291` +- **Date:** 2026-08-01 +- **Run stamp:** `audit run 2026-08-01T15:30:19Z | hub 6501479` + +Supersedes the 2026-07-23 snapshot, which predated the release pipeline. Everything that snapshot listed as a defect has landed: both rulesets are live, `repo-config/` is carried, and the publisher cut release `1.0.9` on 2026-07-23 with the multi-arch image and the executable 7z attached. What remains is a different set, created mostly by the hub advancing rather than by the repo regressing. ## Develop Drift -`develop` vs `main`: ahead 1, behind 3 by commit count - **benign**. The three `main`-only commits are `develop -> main` promotion merge commits whose trees match their develop-side parents, an ancestry gap inherent to merge-commit promotions that carries no content `develop` lacks (the audit's content-based branch check is silent on it, and a cherry-pick would be an empty no-op). The one develop-side commit is normal unreleased work. No action. +`develop` vs `main`: the audit reads both and reports the same findings on each, so `develop` carries no conformance content `main` lacks and vice versa. The commit-count gap is the promotion-merge ancestry artifact recorded before and is **benign**. No action. ## Dimensions | Dimension | Letter | Intent | Verdict | Evidence (file:line) | | --- | --- | --- | --- | --- | -| csharp | fail | fail | drift | `.editorconfig:60` carries the repo-wide `dotnet_analyzer_diagnostic.severity = suggestion` CODESTYLE.md forbids (the hub canonical dropped it in ProjectTemplate#400). `PhotoCleaner/PhotoCleaner.csproj:3-4` sets `AnalysisLevel=latest-all` + `EnableNETAnalyzers=true` but **no `TreatWarningsAsErrors` anywhere**, so analyzers are demoted to suggestions and warnings never fail the build. The ProjectTemplate#353 probe measured what this hides: 362 `xUnit1051` + 2 `xUnit1030`, plus pre-existing `NU1903` (SQLitePCLRaw 2.1.10 high-severity advisory) and 4 `CS8625` that warn without failing anything | -| console | fail | pass | drift | a real System.CommandLine console app (`PhotoCleaner/PhotoCleaner.csproj:9 OutputType=Exe`, `PhotoCleaner/PhotoCleaner.csproj:34 System.CommandLine 2.0.5`, net10.0) but no `build-executable-task.yml` and no release pipeline, so the smoke-subset and `release-asset--` checks have nothing to bind to | -| docker | fail | fail | drift | `Docker/Dockerfile` present but no docker build/push workflow and no `Docker/README.md` - the Dockerfile is dead weight until a pipeline exists | -| branch-model | fail | fail | defect | **no rulesets at all** - `develop` and `main` both unprotected (audit DEFECT x2). No `repo-config/` payloads to import. Branches diverged (see Develop Drift) | -| repo-setup | pass | fail | drift | secrets fully provisioned in both stores (`CODECOV_TOKEN`, `CODEGEN_APP_CLIENT_ID`, `CODEGEN_APP_PRIVATE_KEY` in actions + dependabot) but nothing consumes the App creds - `.github/dependabot.yml` is absent (no dual-target sync keystone) and there is no merge-bot workflow | -| linter-parity | pass | pass | pass | `validate-task.yml:66-88` runs csharpier check, `dotnet format style --verify-no-changes`, markdownlint (SHA-pinned action), cspell (SHA-pinned), actionlint (SHA-pinned), and editorconfig-checker via docker `:latest`. The unit-test job collects coverage and uploads to codecov v7 (`validate-task.yml:36-40`). Matches the fleet lint architecture | -| recurring-violations | pass | pass | pass | `.gitattributes:3` fleet-standard `* -text` with LF pins for `*.sh` and `.husky/pre-commit`. README em-dash grep clean | -| readme-structure | fail | pass | drift | app-focused and thorough (`## Overview:5`, `## Usage:46`, flow sections, `## Docker:415`, `## Development Tooling:474`, `## License:653`) but not the fleet section set - no Build and Distribution block (nothing to badge pre-release), no Table of Contents, no Questions or Issues, Development-Environment-Setup slot filled by `Development Tooling` | -| workflow (WORKFLOW.md 5A/5B) | fail | pass | drift | no publisher, so the 5A publish guarantees are N/A. The PR gate itself is sound - `validate` runs unconditionally and the aggregator carries the canonical ruleset-bound name `Check pull request workflow status job` (`test-pull-request.yml:34-40`, interface contract passes, no paths-filter/smoke by design per the header `test-pull-request.yml:5`) - but with no ruleset the required check binds to nothing, so the gate is advisory until branch-model lands | +| csharp | pass | pass | pass | `Directory.Build.props` carries the analyzer set and `TreatWarningsAsErrors`, `Directory.Packages.props` centralizes versions, and the repo-wide analyzer relaxation the previous snapshot flagged at `.editorconfig:60` is gone. The shared `[*.cs]` block is present | +| console | pass | pass | pass | System.CommandLine console (`PhotoCleaner/PhotoCleaner.csproj`, `OutputType=Exe`, net10.0). `build-executable-task.yml` aggregates per-runtime output to `release-asset--*`, and the smoke matrix is a strict subset | +| docker | pass | pass | pass | `Docker/Dockerfile` multi-arch, `Docker/README.md` present, `build-docker-task.yml` uses a registry layer cache (`buildcache-`), and the image re-pushes on publish | +| branch-model | pass | pass | pass | Both rulesets live and matching `repo-config/develop.json` and `repo-config/main.json` by normalized diff | +| repo-setup | pass | pass | pass | Every name in `spec/secrets.json` present in the store its mechanism claims, and no forbidden name | +| linter-parity | pass | pass | pass | `validate-task.yml:66-88` runs csharpier check, `dotnet format style --verify-no-changes`, markdownlint, cspell, actionlint, and editorconfig-checker. One config per linter | +| recurring-violations | pass | pass | pass | ASCII clean across the carried docs, and `.gitattributes` is fleet-standard with the LF pins | +| readme-structure | fail | fail | defect | Intro line 150 characters against the 100-character cap (`README.md:3`), and the Docker Hub short description does not mirror it. No Build and Distribution block, no Table of Contents, no Questions or Issues, and the Development-Environment-Setup slot is filled by `Development Tooling` (`README.md:482`) | +| workflow (WORKFLOW.md 5A/5B) | fail | pass | drift | The publisher, build tasks, and PR gate satisfy the D-guarantees, **except** that `build-release-task.yml` carries no `validate-release` job, so D2.2 (branch matches version classification) is unimplemented and scenarios S1, S4, and S10 bind to a job name that does not exist. The `github-release` job body matches no hub revision | +| agent-instruction-set | fail | fail | defect | `GOVERNANCE.md` absent, and `AGENTS.md` is the pre-split single file, so neither verbatim region can be compared and all ten of its sections read as undeclared. `.github/copilot-instructions.md` lacks `Reviewing Carried Fleet Content` | nuget, pypi, python: N/A (no packaging, no Python). ## Defects (most severe first) -1. **Both branch rulesets missing** - `develop` and `main` are unprotected: no signed-commit requirement, no PR gate, no required status check, force-push and deletion possible. Import `repo-config/develop.json` + `main.json` via `configure.sh apply` once `repo-config/` is carried. +1. **The agent instruction set predates the router split.** `GOVERNANCE.md` is absent (the only LETTER-class file finding) and `AGENTS.md` still carries the ten topical rule sections inline, so no verbatim region can be compared and every section reads as undeclared. A downstream agent reading this repo gets rule text that no longer tracks the canonical. +2. **README intro over the cap, and the Docker Hub mirror diverged from it.** The intro is 150 characters against the 100-character Docker Hub cap, so it overruns the tightest surface it feeds. Of the two mirrors GOVERNANCE.md "Repository Details" names, the GitHub About panel still matched the README exactly and only the Docker Hub short description had diverged (`Pre-process media files for import into photo management systems.`), so the repo carried two different canonical sentences. ## Drift Findings -- `AGENTS.md` is an old skeleton: 6 of the carried intent sections missing (Branching Model, Release Model, Pull Request Title and Commit Message Conventions, Documentation Style Conventions, PR Review Etiquette, Workflow YAML Conventions) and all 3 verbatim universal sections absent (Repository Boundaries and Write Safety, Git and Commit Rules, Verification Discipline) - re-vendor from the hub. -- `.markdownlint-cli2.jsonc` hand-modified (matches no hub revision) - re-vendor the canonical. -- Absent baseline files (audit LETTERs): `WORKFLOW.md`, `version.json`, `repo-config/` (all six), `AUDIT.md`, `spec/secrets.json`, `.github/dependabot.yml`, `Docker/README.md`. -- `.editorconfig:60` analyzer relaxation + no `TreatWarningsAsErrors` (see csharp dimension) - the ProjectTemplate#353 downstream item, sequenced as its own PR (362 sites). -- Committed `CLAUDE.md` and `PhotoCleaner.code-workspace` at the repo root - repo-local extras. `AGENTS.md` is the fleet's agent-agnostic doc, so a committed `CLAUDE.md` duplicates that role and can drift from it. +- `.markdownlint-cli2.jsonc` matches a past hub revision, so re-vendor it (the base gained `MD033 allowed_elements` for `details` and `summary`). +- `repo-config/configure.sh` matches a past hub revision, so re-vendor it (the base gained the `per_page` cap guard in `ruleset_id` and explicit failure guards on four reads). +- `build-release-task.yml` is missing the `validate-release` job, and its `github-release` body matches no hub revision. +- `version.json` carries a `nugetPackageVersion` block for a repo that publishes no package (STANDUP.md section 2, "carry only the fields the repo uses"). Not a mechanical finding, since `version.json` is checked at `intent`. + +## Convergence in Flight + +Six pull requests opened 2026-08-01 against `develop`, one per drift class per AUDIT.md section 10, each driven to a Copilot review on its head SHA and left for the maintainer to merge: + +- [#26](https://github.com/ptr727/PhotoCleaner/pull/26) the workspace extension set (`gruntfuggly.todo-tree` to `fanaticpythoner.better-todo-tree`) +- [#27](https://github.com/ptr727/PhotoCleaner/pull/27) re-vendor the two stale verbatim carries +- [#28](https://github.com/ptr727/PhotoCleaner/pull/28) the `AGENTS.md` and `GOVERNANCE.md` split, plus `Reviewing Carried Fleet Content` +- [#29](https://github.com/ptr727/PhotoCleaner/pull/29) the `validate-release` entry gate and the re-vendored `github-release` +- [#30](https://github.com/ptr727/PhotoCleaner/pull/30) the README and HISTORY structure +- [#31](https://github.com/ptr727/PhotoCleaner/pull/31) drop the unused `nugetPackageVersion` block ## Proposed Registry / Spec Updates -- Refresh the stale `driftNotes`: the repo is no longer pre-CI (PR gate + linters live). The current gaps are rulesets, `repo-config/`, `version.json`, governance docs, `dependabot.yml`, and the release pipeline. Applied in the same change as this report. -- `releaseTrigger: none` remains accurate until a publisher exists. +- Refresh the `driftNotes`: the second note asserted this report predated the docker and release wiring, which it no longer does. Applied in the same change. + +## Escalations + +Five spec questions this audit surfaced, raised rather than resolved, per AUDIT.md section 9. Filed as issue [#509](https://github.com/ptr727/ProjectTemplate/issues/509). + +1. **The `HISTORY.md` mirror rule has no carried home.** `spec/readme-structure.md` owns it and the audit enforces it, but that file is hub-only, so a downstream repo cannot point at the rule it is measured against. PhotoCleaner kept the rule as repo-local prose in `CODESTYLE.md` for want of a destination. Either promote it into a carried section, or accept that mechanical-only enforcement is the intent. +2. **The hub's own `.github/copilot-instructions.md` still describes the pre-split file.** `Reviewing Carried Fleet Content` says "Most of `AGENTS.md` is universal fleet law: every section that states a rule, as opposed to the two that describe this repository's own directory tree and devcontainer". After the split those sections live in `GOVERNANCE.md`, and `AGENTS.md` carries exactly two verbatim sections and no repo-specific ones. Every repo carrying this section downstream inherits the stale description. +3. **`CODESTYLE.md` contradicts `.markdownlint-cli2.jsonc` on MD033.** The Markdown-linting item says "HTML elements are flagged", but the canonical config now sets `MD033: { allowed_elements: ["details", "summary"] }`. The prose was not swept when the config changed. +4. **`spec/readme-structure.md` assumes a public repository.** PhotoCleaner is private for now, so shields.io cannot read its GitHub release, build, or commit data and every GitHub-sourced badge renders broken, the pre-existing License shield included. The Build Status and Releases sub-sections state no behavior for that case. The spec question stands even though this repo resolves on its own: a repo is often private while it is being made presentable, which is exactly when its README is being written. +5. **`WORKFLOW.md` D2.2 "skipped on smoke" is ambiguous, and a reviewer misread it.** The phrase names the validation, and scenario S1 confirms it (`validate-release **skipped (smoke), succeeds**`), but a Copilot review read it as the GitHub job status and proposed a job-level `if: !inputs.smoke` that would have coupled `github-release` to smoke through its `needs`. Worth disambiguating in the D-guarantee text. + +A sixth question was raised with the maintainer and is **answered**: the repository is **private** while its Docker image is public, so the declared `github-release` channel with `consumerModel: pull` is not currently satisfiable. That is deliberate and temporary. The repo goes public once the conformance work settles, which serves prospective users and lowers the GitHub bill, and the declared channel becomes correct at that flip rather than being wrong now. The `driftNotes` record it, and the README gains its GitHub build and release shields at the same time. From f353630f51fe13b548d09aefda974cd184617154 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 8 Aug 2026 02:24:52 +0000 Subject: [PATCH 25/32] Bump the actions-deps group with 4 updates Bumps the actions-deps group with 4 updates: [actions/setup-dotnet](https://github.com/actions/setup-dotnet), [actions/checkout](https://github.com/actions/checkout), [softprops/action-gh-release](https://github.com/softprops/action-gh-release) and [DavidAnson/markdownlint-cli2-action](https://github.com/davidanson/markdownlint-cli2-action). Updates `actions/setup-dotnet` from 5.3.0 to 6.0.0 - [Release notes](https://github.com/actions/setup-dotnet/releases) - [Commits](https://github.com/actions/setup-dotnet/compare/9a946fdbd5fb07b82b2f5a4466058b876ab72bb2...a98b56852c35b8e3190ac28c8c2271da59106c68) Updates `actions/checkout` from 7.0.0 to 7.0.1 - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0...3d3c42e5aac5ba805825da76410c181273ba90b1) Updates `softprops/action-gh-release` from 3.0.1 to 3.0.2 - [Release notes](https://github.com/softprops/action-gh-release/releases) - [Changelog](https://github.com/softprops/action-gh-release/blob/master/CHANGELOG.md) - [Commits](https://github.com/softprops/action-gh-release/compare/718ea10b132b3b2eba29c1007bb80653f286566b...3d0d9888cb7fd7b750713d6e236d1fcb99157228) Updates `DavidAnson/markdownlint-cli2-action` from 24.0.0 to 24.2.0 - [Release notes](https://github.com/davidanson/markdownlint-cli2-action/releases) - [Commits](https://github.com/davidanson/markdownlint-cli2-action/compare/8de2aa07cae85fd17c0b35642db70cf5495f1d25...21c1be1b93ad9ed58fa840aacc3f279cde2a72ff) --- updated-dependencies: - dependency-name: actions/setup-dotnet dependency-version: 6.0.0 dependency-type: direct:production update-type: version-update:semver-major dependency-group: actions-deps - dependency-name: actions/checkout dependency-version: 7.0.1 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: actions-deps - dependency-name: softprops/action-gh-release dependency-version: 3.0.2 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: actions-deps - dependency-name: DavidAnson/markdownlint-cli2-action dependency-version: 24.2.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: actions-deps ... Signed-off-by: dependabot[bot] --- .github/workflows/publish-release.yml | 6 +++--- .github/workflows/validate-task.yml | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/publish-release.yml b/.github/workflows/publish-release.yml index ec149e86..3775ec0f 100644 --- a/.github/workflows/publish-release.yml +++ b/.github/workflows/publish-release.yml @@ -39,13 +39,13 @@ jobs: fi - name: Setup .NET SDK step - uses: actions/setup-dotnet@9a946fdbd5fb07b82b2f5a4466058b876ab72bb2 # v5.3.0 + uses: actions/setup-dotnet@a98b56852c35b8e3190ac28c8c2271da59106c68 # v6.0.0 with: dotnet-version: 10.x # Full history for NBGV; pin the dispatch-time commit - a push landing after dispatch must not release unvalidated. - name: Checkout code step - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: ref: ${{ github.sha }} fetch-depth: 0 @@ -60,7 +60,7 @@ jobs: # The target_commitish input pins the tag to the exact built commit, GitCommitId, rather than to the default branch. # The release is the tag plus GitHub's auto source archive, README and LICENSE, carrying no build assets because the repo is source-only. - name: Create GitHub release step - uses: softprops/action-gh-release@718ea10b132b3b2eba29c1007bb80653f286566b # v3.0.1 + uses: softprops/action-gh-release@3d0d9888cb7fd7b750713d6e236d1fcb99157228 # v3.0.2 with: generate_release_notes: true tag_name: ${{ steps.nbgv.outputs.SemVer2 }} diff --git a/.github/workflows/validate-task.yml b/.github/workflows/validate-task.yml index 8a0ce712..92c65133 100644 --- a/.github/workflows/validate-task.yml +++ b/.github/workflows/validate-task.yml @@ -17,12 +17,12 @@ jobs: steps: - name: Checkout code step - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 # Doc linters run as pinned action wrappers. # The editorconfig-checker action is install-only, so it runs via Docker instead. - name: Lint Markdown step - uses: DavidAnson/markdownlint-cli2-action@8de2aa07cae85fd17c0b35642db70cf5495f1d25 # v24.0.0 + uses: DavidAnson/markdownlint-cli2-action@21c1be1b93ad9ed58fa840aacc3f279cde2a72ff # v24.2.0 with: globs: '**/*.md' From 9849fba0f1a711f30b9f13d0fda0e497b4b3439c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 16 Aug 2026 21:08:32 +0000 Subject: [PATCH 26/32] Bump astral-sh/setup-uv from 8.1.0 to 10.0.0 in the actions-deps group Bumps the actions-deps group with 1 update: [astral-sh/setup-uv](https://github.com/astral-sh/setup-uv). Updates `astral-sh/setup-uv` from 8.1.0 to 10.0.0 - [Release notes](https://github.com/astral-sh/setup-uv/releases) - [Commits](https://github.com/astral-sh/setup-uv/compare/08807647e7069bb48b6ef5acd8ec9567f424441b...ae62891fec2bb8e7d6c99fc78c9fec3a63790f8d) --- updated-dependencies: - dependency-name: astral-sh/setup-uv dependency-version: 10.0.0 dependency-type: direct:production update-type: version-update:semver-major dependency-group: actions-deps ... Signed-off-by: dependabot[bot] --- .github/workflows/validate-task.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/validate-task.yml b/.github/workflows/validate-task.yml index 361ce5d9..bcc35773 100644 --- a/.github/workflows/validate-task.yml +++ b/.github/workflows/validate-task.yml @@ -116,7 +116,7 @@ jobs: # This is #729, decided here, the one place the fleet's uvx tools are pinned or floated. - name: Setup uv step if: hashFiles('pyproject.toml') != '' - uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0 + uses: astral-sh/setup-uv@ae62891fec2bb8e7d6c99fc78c9fec3a63790f8d # v10.0.0 with: python-version: "3.13" @@ -230,7 +230,7 @@ jobs: - name: Setup uv step if: hashFiles('pyproject.toml') != '' && hashFiles('tests/**') != '' && hashFiles('uv.lock') != '' - uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0 + uses: astral-sh/setup-uv@ae62891fec2bb8e7d6c99fc78c9fec3a63790f8d # v10.0.0 with: python-version: "3.13" From df79b095a13c75a737d5f26806f5da1bfae9ed84 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 17 Aug 2026 12:27:40 +0000 Subject: [PATCH 27/32] Bump astral-sh/setup-uv from 10.0.0 to 10.0.1 in the actions-deps group Bumps the actions-deps group with 1 update: [astral-sh/setup-uv](https://github.com/astral-sh/setup-uv). Updates `astral-sh/setup-uv` from 10.0.0 to 10.0.1 - [Release notes](https://github.com/astral-sh/setup-uv/releases) - [Commits](https://github.com/astral-sh/setup-uv/compare/ae62891fec2bb8e7d6c99fc78c9fec3a63790f8d...20cfd1bf945f4377ade1205e4dbc17946fc9a30d) --- updated-dependencies: - dependency-name: astral-sh/setup-uv dependency-version: 10.0.1 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: actions-deps ... Signed-off-by: dependabot[bot] --- .github/workflows/validate-task.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/validate-task.yml b/.github/workflows/validate-task.yml index bcc35773..28c4e5c0 100644 --- a/.github/workflows/validate-task.yml +++ b/.github/workflows/validate-task.yml @@ -116,7 +116,7 @@ jobs: # This is #729, decided here, the one place the fleet's uvx tools are pinned or floated. - name: Setup uv step if: hashFiles('pyproject.toml') != '' - uses: astral-sh/setup-uv@ae62891fec2bb8e7d6c99fc78c9fec3a63790f8d # v10.0.0 + uses: astral-sh/setup-uv@20cfd1bf945f4377ade1205e4dbc17946fc9a30d # v10.0.1 with: python-version: "3.13" @@ -230,7 +230,7 @@ jobs: - name: Setup uv step if: hashFiles('pyproject.toml') != '' && hashFiles('tests/**') != '' && hashFiles('uv.lock') != '' - uses: astral-sh/setup-uv@ae62891fec2bb8e7d6c99fc78c9fec3a63790f8d # v10.0.0 + uses: astral-sh/setup-uv@20cfd1bf945f4377ade1205e4dbc17946fc9a30d # v10.0.1 with: python-version: "3.13" From 2d360ef2b169ef67d24313e8b0fe237c42cc1eac Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 18 Aug 2026 12:25:22 +0000 Subject: [PATCH 28/32] Bump streetsidesoftware/cspell-action in the actions-deps group Bumps the actions-deps group with 1 update: [streetsidesoftware/cspell-action](https://github.com/streetsidesoftware/cspell-action). Updates `streetsidesoftware/cspell-action` from 8.4.0 to 9.0.1 - [Release notes](https://github.com/streetsidesoftware/cspell-action/releases) - [Changelog](https://github.com/streetsidesoftware/cspell-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/streetsidesoftware/cspell-action/compare/de2a73e963e7443969755b648a1008f77033c5b2...e0668cf020899e887ee8ad4d173c31738a79eae8) --- updated-dependencies: - dependency-name: streetsidesoftware/cspell-action dependency-version: 9.0.1 dependency-type: direct:production update-type: version-update:semver-major dependency-group: actions-deps ... Signed-off-by: dependabot[bot] --- .github/workflows/validate-task.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/validate-task.yml b/.github/workflows/validate-task.yml index 64617483..faa39a4e 100644 --- a/.github/workflows/validate-task.yml +++ b/.github/workflows/validate-task.yml @@ -36,7 +36,7 @@ jobs: # The spell check covers README + HISTORY only, per CODESTYLE.md "Markdown and Spelling". - name: Spell check step - uses: streetsidesoftware/cspell-action@de2a73e963e7443969755b648a1008f77033c5b2 # v8.4.0 + uses: streetsidesoftware/cspell-action@e0668cf020899e887ee8ad4d173c31738a79eae8 # v9.0.1 with: files: | README.md From 105fe3498126d14a9253a3cda16861f8f961a89d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 20 Aug 2026 12:25:30 +0000 Subject: [PATCH 29/32] Bump docker/setup-buildx-action in the actions-deps group Bumps the actions-deps group with 1 update: [docker/setup-buildx-action](https://github.com/docker/setup-buildx-action). Updates `docker/setup-buildx-action` from 4.2.0 to 4.3.0 - [Release notes](https://github.com/docker/setup-buildx-action/releases) - [Commits](https://github.com/docker/setup-buildx-action/compare/bb05f3f5519dd87d3ba754cc423b652a5edd6d2c...37fe631027851001ddb9b187196cc803df7f5f0e) --- updated-dependencies: - dependency-name: docker/setup-buildx-action dependency-version: 4.3.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: actions-deps ... Signed-off-by: dependabot[bot] --- .github/workflows/build-docker-task.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-docker-task.yml b/.github/workflows/build-docker-task.yml index 45287b82..2d2535d7 100644 --- a/.github/workflows/build-docker-task.yml +++ b/.github/workflows/build-docker-task.yml @@ -203,7 +203,7 @@ jobs: platforms: arm64 - name: Setup Buildx step - uses: docker/setup-buildx-action@bb05f3f5519dd87d3ba754cc423b652a5edd6d2c # v4.2.0 + uses: docker/setup-buildx-action@37fe631027851001ddb9b187196cc803df7f5f0e # v4.3.0 with: platforms: ${{ env.PLATFORMS }} From bd627ed52083db9df9db39b0220ef1e3b27cddf5 Mon Sep 17 00:00:00 2001 From: Pieter Viljoen Date: Tue, 25 Aug 2026 16:47:17 -0700 Subject: [PATCH 30/32] Normalize a Dependabot Pin Bump Out of the Intent Staleness Advisory ## What The intent-staleness advisory compares two dates: a downstream copy's last commit against the hub canonical's last commit, and read no content at all. The verbatim engine already normalizes three classes of governed drift before hashing (spec/fidelity-model.md "Normalization"): line endings, a `uses: @` pin with its trailing version comment, and a job's `needs:` list. The intent advisory applied none of that, so a Dependabot pin bump on a workflow file's hub canonical marked every downstream carrier as "possibly trailing" at once, for a class of drift the fidelity model already treats as governed per-repo churn rather than a deviation. ## Fix `hub_last_change()` now walks the canonical's full git history and returns the newest revision whose normalized content differs from its predecessor's (`_last_effective_change`), falling back to the file's creation revision if every bump back to it was normalized-only. `git_file_history()` and `hub_last_change()` now share one cached history walk (`_git_revisions`) instead of two separate `git log` calls. Verified live against the two files named in ptr727/ProjectTemplate#735: `publish-release.yml` now dates from a real job-condition change (#844) instead of a pin-only Dependabot bump (#612), and `validate-task.yml` picks up its most recent real change. Added self-test coverage for `_last_effective_change` (pin-only chain back to creation, a real change under a later pin bump, a single-revision file, and unreadable history treated as effective rather than silently skipped). Updated the fidelity-model.md "intent" description and the `check_intent_staleness`/`hub_last_change` docstrings to state the normalization explicitly. ruff, ruff format, mypy, the audit self-test suite, prose_lint.py, repo_gate.py, and host_gate.py all pass clean. Fixes #735. --- spec/audit.py | 151 ++++++++++++++++++++++++++++++----------- spec/fidelity-model.md | 2 +- 2 files changed, 112 insertions(+), 41 deletions(-) diff --git a/spec/audit.py b/spec/audit.py index c696dac4..0cf899ff 100755 --- a/spec/audit.py +++ b/spec/audit.py @@ -1714,42 +1714,66 @@ def classify_verbatim(down_text, canon_text, past_texts): return "modified" -_HISTORY_CACHE: dict[ - str, list[str] -] = {} # rel_path -> past revision contents, cached because one canonical is compared against every audited repo - +@functools.cache +def _git_revisions(rel_path): + """Every commit that touched rel_path in the hub's history, newest first, as (date, sha, text). -def git_file_history(rel_path): - """Every past revision's content of a hub-tracked file (to tell a stale copy from a modified one), cached per rel_path.""" - if rel_path in _HISTORY_CACHE: - return _HISTORY_CACHE[rel_path] - out = [] - # Decode as UTF-8 with replacement to match the downstream and canonical reads. - # A divergent decode would fabricate a mismatch. + `text` is None where `git show` failed (rare: a permission or encoding fluke, never absence - + the commit came from `git log -- rel_path`, so the path existed at that revision). Cached + because one canonical's history is read once per fidelity/staleness check, then reused for + every audited repo's copy. + """ r = subprocess.run( - ["git", "log", "--format=%H", "--", rel_path], + ["git", "log", "--format=%cI %H", "--", rel_path], cwd=ROOT, capture_output=True, - encoding="utf-8", - errors="replace", + text=True, check=False, ) - if r.returncode == 0: - for sha in r.stdout.split(): - s = subprocess.run( - ["git", "show", f"{sha}:{rel_path}"], - cwd=ROOT, - capture_output=True, - encoding="utf-8", - errors="replace", - check=False, - ) - if s.returncode == 0: - out.append(s.stdout) - _HISTORY_CACHE[rel_path] = out + if r.returncode != 0 or not r.stdout.strip(): + return [] + out = [] + for line in r.stdout.splitlines(): + date, sha = line.split(" ", 1) + # Decode as UTF-8 with replacement to match the downstream and canonical reads. + # A divergent decode would fabricate a mismatch. + s = subprocess.run( + ["git", "show", f"{sha}:{rel_path}"], + cwd=ROOT, + capture_output=True, + encoding="utf-8", + errors="replace", + check=False, + ) + out.append((date, sha, s.stdout if s.returncode == 0 else None)) return out +def git_file_history(rel_path): + """Every past revision's content of a hub-tracked file (to tell a stale copy from a modified one).""" + return [text for _, _, text in _git_revisions(rel_path) if text is not None] + + +def _last_effective_change(revisions): + """The (date, sha) of the newest revision in `revisions` (newest-first (date, sha, text) + triples for one file) whose content differs from its predecessor after normalize() - or the + oldest (creation) revision, if every later one differs from its predecessor only by normalized + churn (spec/fidelity-model.md "Normalization": EOL, a Dependabot action-pin bump, a pruned + `needs:` list). None if `revisions` is empty. + + The creation revision always counts as effective: it has no predecessor, and normalize() + applied to only one side proves nothing. A revision with unreadable text (None) also counts as + effective rather than being silently skipped, since a real difference cannot be ruled out. + """ + for i, (date, sha, text) in enumerate(revisions): + if i + 1 == len(revisions): + return date, sha + older_text = revisions[i + 1][2] + if text is None or older_text is None or normalize(text) != normalize(older_text): + return date, sha + return None + + @functools.cache def git_blob_in_file_history(rel_path, blob_sha): """Whether a blob occurred in a path's hub history.""" @@ -1765,21 +1789,22 @@ def git_blob_in_file_history(rel_path, blob_sha): @functools.cache def hub_last_change(rel_path): - """The hub checkout's last commit touching rel_path, as (iso_date, short_sha), or None if untracked. + """The hub checkout's most recent EFFECTIVE change to rel_path, as (iso_date, short_sha), or + None if untracked. + + "Effective" excludes normalized churn (spec/fidelity-model.md "Normalization": EOL, a + Dependabot action-pin bump, a pruned `needs:` list) the same way the verbatim check already + does, via _last_effective_change over the file's full history. A raw last-commit date treated + every one of those bumps as the copy "trailing", even though the fidelity model already + classifies that class as governed per-repo drift rather than a deviation (ptr727/ProjectTemplate#735). Cached because one canonical's date is compared against every audited repo's copy. """ - r = subprocess.run( - ["git", "log", "-1", "--format=%cI %h", "--", rel_path], - cwd=ROOT, - capture_output=True, - text=True, - check=False, - ) - if r.returncode != 0 or not r.stdout.strip(): + change = _last_effective_change(_git_revisions(rel_path)) + if change is None: return None - date, sha = r.stdout.strip().split(" ", 1) - return date, sha + date, sha = change + return date, sha[:7] def intent_canonical_rel(item, path): @@ -1810,8 +1835,10 @@ def check_intent_staleness(slug, ground, path, canonical_rel, down_text): (spec/fidelity-model.md), which is how a copy trailed the hub by many revisions while every check read clean. No reconciliation record exists anywhere, so the implementable proxy is when each side last changed: the hub canonical changing after the repo's copy marks the copy - as possibly trailing. Advisory only, DRIFT and never a failure, and honest about its blind - spot: a copy touched after the hub change without actually reconciling reads current. + as possibly trailing. "Changed" excludes normalized churn (hub_last_change), so a Dependabot + action-pin bump or a needs-list prune does not by itself mark every carrier as trailing. + Advisory only, DRIFT and never a failure, and honest about its blind spot: a copy touched + after the hub change without actually reconciling reads current. A copy content-identical to the canonical cannot trail it, so that case is skipped however old the copy's last commit is. It is also the promotion candidate spec/fidelity_honesty.py @@ -3158,6 +3185,50 @@ def _selftest(): " ok needs-mask: pruned needs (inline, block, scalar) normalizes equal, forked step differs, next key preserved" ) + # _last_effective_change: the intent-staleness date must skip a normalized-only bump (a + # Dependabot pin, per ptr727/ProjectTemplate#735) and keep walking history for a real change, + # falling back to the creation revision if every bump back to it was normalized-only. + d3, d2, d1 = ( + "2024-03-01T00:00:00+00:00", + "2024-02-01T00:00:00+00:00", + "2024-01-01T00:00:00+00:00", + ) + lec_cases = [ + ( + "every bump back to creation is pin-only -> creation wins", + [(d3, "sha3", pin_b), (d2, "sha2", pin_a), (d1, "sha1", pin_a)], + (d1, "sha1"), + ), + ( + "newest differs for real -> newest wins", + [(d3, "sha3", pin_struct), (d2, "sha2", pin_a), (d1, "sha1", pin_a)], + (d3, "sha3"), + ), + ( + "newest is a pin-only bump over a real change -> the real change wins", + [(d3, "sha3", pin_b), (d2, "sha2", pin_a), (d1, "sha1", pin_struct)], + (d2, "sha2"), + ), + ( + "one revision (creation) -> that revision wins, nothing to compare against", + [(d1, "sha1", "only revision\n")], + (d1, "sha1"), + ), + ( + "unreadable newest text -> treated as effective, never silently skipped", + [(d2, "sha2", None), (d1, "sha1", "whatever\n")], + (d2, "sha2"), + ), + ("no history -> None", [], None), + ] + for label, revisions, want in lec_cases: + got = _last_effective_change(revisions) + if got != want: + ok = False + print( + f" {'ok ' if got == want else 'FAIL'} want={want!s:<24} got={got!s:<24} _last_effective_change: {label}" + ) + # Region extraction and hashing: a forked github-release block must hash differently from the canonical. region = split_jobs(rel_ok).get("github-release") forked_region = split_jobs( diff --git a/spec/fidelity-model.md b/spec/fidelity-model.md index a921cafc..8d514b5f 100644 --- a/spec/fidelity-model.md +++ b/spec/fidelity-model.md @@ -11,7 +11,7 @@ Carried content is a class with virtual functions. The **fixed** part is the int Each [`spec/files.json`][files] entry declares one `fidelity`, defaulting to `presence`. - **presence** - the unit exists (a file, or a Markdown section heading). The audit's baseline check. -- **intent** - carried faithfully but judged by meaning, not bytes. A downstream copy legitimately differs (a governed divergence or a paraphrase), and equivalence is a human call via `intentRef`. The audit asserts presence, plus a last-modified staleness advisory at drift: a hub canonical changing after the copy's own last commit marks the copy as possibly trailing, a hint rather than proof, and content is never judged. +- **intent** - carried faithfully but judged by meaning, not bytes. A downstream copy legitimately differs (a governed divergence or a paraphrase), and equivalence is a human call via `intentRef`. The audit asserts presence, plus a last-modified staleness advisory at drift: a hub canonical changing after the copy's own last commit marks the copy as possibly trailing, a hint rather than proof, and content is never judged. That "changing" walks past a revision whose diff is normalized-only (the same line-ending, action-pin, and job-needs normalization as verbatim below), so a Dependabot pin bump on a workflow file does not by itself mark every carrier as trailing (ptr727/ProjectTemplate#735). - **verbatim** - byte-identical to the hub's canonical after line-ending, action-pin, and job-needs normalization. The audit content-hashes the downstream copy against canonical. It applies to a whole file, a workflow job region (a job selected by key), or a Markdown section region (a `## heading` block selected by name). The section granularity lets one file be **intent overall while a few of its sections are verbatim**. A universal rule block stays byte-identical fleet-wide even though the rest of the document is a repo-adapted paraphrase, so a stale section or a missing rule is caught while its heading still passes the presence check. - **interface** - an overridable body that must honor a named contract. The audit checks the contract by name and wiring, never the body. From 6a769e62d0a31bc227f3e09a751a40d7710354ce Mon Sep 17 00:00:00 2001 From: Pieter Viljoen Date: Tue, 25 Aug 2026 16:57:06 -0700 Subject: [PATCH 31/32] Address CodeRabbit and Qodo Review Findings on PR #1014 - _git_revisions() now raises on a genuine `git log` execution failure instead of silently returning an empty history, which previously read identically to "no history" and would have cleared the intent-staleness advisory or dropped verbatim's past-revision list on a tool fault rather than reporting it (CodeRabbit). - Replaced a spaced-hyphen interruption in _git_revisions()'s docstring with a comma, per CODESTYLE.md's ASCII punctuation rule (Qodo). - Shortened the three-line _last_effective_change self-test intro comment to one line (Qodo). --- spec/audit.py | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/spec/audit.py b/spec/audit.py index 0cf899ff..e71de672 100755 --- a/spec/audit.py +++ b/spec/audit.py @@ -1718,10 +1718,10 @@ def classify_verbatim(down_text, canon_text, past_texts): def _git_revisions(rel_path): """Every commit that touched rel_path in the hub's history, newest first, as (date, sha, text). - `text` is None where `git show` failed (rare: a permission or encoding fluke, never absence - - the commit came from `git log -- rel_path`, so the path existed at that revision). Cached - because one canonical's history is read once per fidelity/staleness check, then reused for - every audited repo's copy. + `text` is None where `git show` failed (rare: a permission or encoding fluke, not absence, + since the commit came from `git log -- rel_path` and so the path existed at that revision). + Cached because one canonical's history is read once per fidelity/staleness check, then reused + for every audited repo's copy. """ r = subprocess.run( ["git", "log", "--format=%cI %H", "--", rel_path], @@ -1730,7 +1730,12 @@ def _git_revisions(rel_path): text=True, check=False, ) - if r.returncode != 0 or not r.stdout.strip(): + if r.returncode != 0: + # A real command failure (not a git repo, a corrupt object) must not read as "no + # history": that silently clears the intent-staleness advisory and drops verbatim's + # past-revision list, both misreporting a tool fault as a clean audit. + raise RuntimeError(f"git log failed for {rel_path}: {r.stderr.strip()}") + if not r.stdout.strip(): return [] out = [] for line in r.stdout.splitlines(): @@ -3185,9 +3190,7 @@ def _selftest(): " ok needs-mask: pruned needs (inline, block, scalar) normalizes equal, forked step differs, next key preserved" ) - # _last_effective_change: the intent-staleness date must skip a normalized-only bump (a - # Dependabot pin, per ptr727/ProjectTemplate#735) and keep walking history for a real change, - # falling back to the creation revision if every bump back to it was normalized-only. + # _last_effective_change must skip a normalized-only bump, per ptr727/ProjectTemplate#735. d3, d2, d1 = ( "2024-03-01T00:00:00+00:00", "2024-02-01T00:00:00+00:00", From c0f7afdd53eb6b14c1a0f8c2dad59e7971448d8d Mon Sep 17 00:00:00 2001 From: Pieter Viljoen Date: Tue, 25 Aug 2026 16:59:01 -0700 Subject: [PATCH 32/32] Document _last_effective_change's Linear-History Assumption Qodo flagged a real theoretical gap: comparing adjacent git-log entries only identifies the actual predecessor when a canonical file's history is a single line, not a branching graph. Verified empirically that every intent-fidelity canonical file's full history in this repo satisfies that today (0 non-ancestor adjacent pairs across AGENTS.md, WORKFLOW.md, GOVERNANCE.md, CODESTYLE.md, and both workflow files named in #735, spanning their combined 344 commits), which this repo's forward-only branching model (no back-merges, squash-only feature merges) makes structural rather than incidental. Documented the assumption and its failure mode instead of leaving it implicit. Also fixed a spaced-hyphen sentence interruption the same docstring introduced, per CODESTYLE.md's ASCII punctuation rule. --- spec/audit.py | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/spec/audit.py b/spec/audit.py index e71de672..0f38a7e4 100755 --- a/spec/audit.py +++ b/spec/audit.py @@ -1761,14 +1761,23 @@ def git_file_history(rel_path): def _last_effective_change(revisions): """The (date, sha) of the newest revision in `revisions` (newest-first (date, sha, text) - triples for one file) whose content differs from its predecessor after normalize() - or the - oldest (creation) revision, if every later one differs from its predecessor only by normalized + triples for one file) whose content differs from its predecessor after normalize(), or the + oldest (creation) revision if every later one differs from its predecessor only by normalized churn (spec/fidelity-model.md "Normalization": EOL, a Dependabot action-pin bump, a pruned `needs:` list). None if `revisions` is empty. The creation revision always counts as effective: it has no predecessor, and normalize() applied to only one side proves nothing. A revision with unreadable text (None) also counts as effective rather than being silently skipped, since a real difference cannot be ruled out. + + `revisions` is assumed newest-first with each entry the immediate predecessor of the one + before it (verified empirically over every intent-fidelity canonical file's full history, + ptr727/ProjectTemplate#1014): this repo's own branching is forward-only (no back-merges from + main into develop) with feature branches squash-merged one at a time, so a canonical file's + per-path `git log` is a single line, not a graph with siblings to mis-order. A canonical file + reached through a genuinely branching history (a direct hotfix to main alongside independent + develop work touching the same path) would need each revision compared against its actual git + parent(s) instead of its list neighbor. """ for i, (date, sha, text) in enumerate(revisions): if i + 1 == len(revisions):