Skip to content

feat(landing): drive organ nav + sync date from a single data source#3

Merged
4444J99 merged 5 commits into
mainfrom
claude/issue-discovery-reporting-C5ZPZ
May 26, 2026
Merged

feat(landing): drive organ nav + sync date from a single data source#3
4444J99 merged 5 commits into
mainfrom
claude/issue-discovery-reporting-C5ZPZ

Conversation

@4444J99

@4444J99 4444J99 commented May 26, 2026

Copy link
Copy Markdown
Collaborator

Summary

Normalizes the landing page's hardcoded dynamic data (organ nav URLs + footer sync date) into a single source of truth — part of the "normalize dynamic data" pass.

  • data/site.json — single source for the organ-nav entries (the *.github.io URLs that duplicate the organ→org map) and the footer "System Synchronization" date.
  • scripts/sync-site.py — renders that data into index.html:
    • the <!-- organs:start -->...<!-- organs:end --> nav block (HTML-escaped, preserves the active state),
    • the inline <!-- v:synced -->...<!-- /v --> footer date.
    • Pure standard library — no third-party deps. --check mode fails on drift; SITE_DATA / SITE_HTML env overrides.
  • scripts/test_sync_site.pyunittest coverage for rendering, escaping, idempotency, orphan handling, and a guard asserting the committed index.html already matches the committed data.
  • .github/workflows/site-sync.yml — runs the tests, verifies sync on PRs, and auto-commits regenerated HTML on push/dispatch.
  • .gitignore — ignore Python bytecode.

No visible change: the rendered index.html is byte-identical to main apart from the marker comments (the data file holds the current values).

Test plan

  • python3 scripts/test_sync_site.py — 7 passing
  • python3 scripts/sync-site.py --check — in sync (exit 0)
  • git diff main -- index.html shows only the added marker comments
  • Drift case (bumped the date) → --check exits 1; write mode fixes it; restore leaves the page unchanged
  • site-sync workflow green on this PR

https://claude.ai/code/session_017iav9RLCuHkepAqnGWYMKo


Generated by Claude Code

Summary by Sourcery

Normalize the landing page’s organ navigation and footer sync date to be generated from a shared data file and enforced via automation.

New Features:

  • Introduce a site data JSON file as the single source of truth for organ navigation links and the footer synchronization date.
  • Add a sync script to render dynamic values and navigation markup into the landing page from the shared data file.

Enhancements:

  • Annotate the landing page HTML with markers to delimit the generated navigation block and the synchronized footer date.

CI:

  • Add a GitHub Actions workflow to run sync script tests, verify HTML is in sync on pull requests, and auto-commit regenerated HTML on pushes or manual runs.

Tests:

  • Add Python unit tests covering navigation rendering, value substitution, escaping, idempotency, and ensuring the committed landing page is in sync with the data file.

Chores:

  • Ignore Python bytecode artifacts in version control.

claude added 3 commits May 24, 2026 15:58
GitHub Pages hosts are lowercase; normalize the uppercase host in the
ecosystem and repo-card links.

https://claude.ai/code/session_017iav9RLCuHkepAqnGWYMKo
Add data/site.json as the single source of truth for the landing page's
dynamic data (the organ nav URLs and the footer sync date), and
scripts/sync-site.py to render it into index.html via <!-- organs:start/end -->
block markers and a <!-- v:synced --> value marker. Pure stdlib (no deps);
--check guards against drift; SITE_DATA / SITE_HTML env overrides. The
site-sync workflow runs the tests, verifies sync on PRs, and auto-commits on
push/dispatch. No visible change — rendered output is byte-identical.

https://claude.ai/code/session_017iav9RLCuHkepAqnGWYMKo
@sourcery-ai

sourcery-ai Bot commented May 26, 2026

Copy link
Copy Markdown

Reviewer's Guide

Centralizes the landing page’s dynamic organ navigation and footer sync date into a JSON data file, adds a Python sync script plus tests to regenerate/index.html from that data, and wires a GitHub Actions workflow to enforce sync and auto-commit updates, with minimal HTML markers added to index.html and Python artifacts ignored via .gitignore.

Sequence diagram for site-sync GitHub Actions workflow

sequenceDiagram
  participant GitHub as GitHub
  participant Workflow as SiteSyncWorkflow
  participant PyTest as scripts_test_sync_site_py
  participant SyncCheck as scripts_sync_site_py_check
  participant SyncWrite as scripts_sync_site_py
  participant Git as git

  GitHub->>Workflow: trigger push_or_pull_request
  Workflow->>PyTest: python3 scripts/test_sync_site.py
  PyTest-->>Workflow: tests_pass
  alt event_is_pull_request
    Workflow->>SyncCheck: python3 scripts/sync-site.py --check
    SyncCheck-->>Workflow: exit_status
  else event_is_push_or_manual
    Workflow->>SyncWrite: python3 scripts/sync-site.py
    SyncWrite-->>Workflow: index_html_updated
    Workflow->>Git: git diff --quiet index.html
    alt index_html_changed
      Workflow->>Git: git add index.html
      Workflow->>Git: git commit
      Workflow->>Git: git push
    end
  end
Loading

File-Level Changes

Change Details Files
Annotate index.html so the organ navigation block and footer sync date can be machine-regenerated without altering existing layout/content.
  • Wrap the existing organ nav
  • list with and marker comments to define a replaceable block.
  • Wrap the footer System Synchronization date with ... so it can be driven from structured data while leaving surrounding text unchanged.
index.html
Introduce a sync script that renders dynamic content into index.html from a single JSON data source, with check mode, environment overrides, and warning reporting.
  • Add scripts/sync-site.py that reads data/site.json and index.html (paths overridable via SITE_DATA and SITE_HTML), then replaces value markers ... with data['values'][KEY] and regenerates the organs nav block from data['organs'].
  • Implement render_organs to HTML-escape URL and label fields, respect an optional active flag, and render
  • lines at a fixed 12-space indentation.
  • Implement a render function that tracks seen value keys, emits warnings for missing data entries or unused values, and replaces the organs:start/end block if present, leaving HTML unchanged otherwise.
  • Add CLI handling for normal write mode (rewrites index.html if needed) and --check mode (exits non-zero and prints an error when index.html is out of sync).
scripts/sync-site.py
index.html
data/site.json
Add unit test coverage for the sync script’s rendering semantics and guard that the committed index.html stays in sync with data/site.json.
  • Load scripts/sync-site.py as a module within scripts/test_sync_site.py using importlib to avoid altering the main script.
  • Test render_organs for correct active/inactive class handling and correct HTML escaping of labels and URLs.
  • Test render for value substitution, organs block regeneration, warning behavior for orphan markers/values, and idempotency when applied repeatedly with the same data.
  • Add an integration-style test that re-renders the real index.html using data/site.json and asserts the output matches, ensuring committed HTML remains synced with the data file.
scripts/test_sync_site.py
scripts/sync-site.py
index.html
data/site.json
Enforce site sync in CI and auto-commit regenerated HTML on pushes or manual workflow runs.
  • Add a Site Sync GitHub Actions workflow that runs on pushes affecting data/site.json, scripts/sync-site.py, or the workflow itself; on PRs affecting index.html, the data, or the script; and on workflow_dispatch.
  • Configure the workflow to set up Python 3.12, run the test suite, and in pull_request events run scripts/sync-site.py --check to fail on drift.
  • For push and manual events, run the sync script, and if index.html changed, auto-commit and push the updated HTML with a standardized commit message and CI skip flag.
  • Grant contents: write permission required for committing from the workflow.
.github/workflows/site-sync.yml
scripts/sync-site.py
scripts/test_sync_site.py
data/site.json
index.html
Housekeeping to support the new Python tooling and data source.
  • Create data/site.json as the single source of truth for organ navigation entries and footer synchronization values consumed by the sync script.
  • Update .gitignore to exclude Python bytecode artifacts (e.g., pycache/ *.pyc) from version control.
data/site.json
.gitignore

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a synchronization mechanism to dynamically inject landing page data from a single source of truth (data/site.json) into index.html using a Python script (scripts/sync-site.py), complete with unit tests. The review feedback correctly identifies potential cross-platform compatibility issues on Windows systems, where default system encodings could cause UnicodeDecodeError when reading or writing files containing non-ASCII characters. It is recommended to explicitly specify encoding="utf-8" in all file read and write operations.

Comment thread scripts/sync-site.py Outdated
Comment on lines +83 to +84
data = json.loads(data_path.read_text())
original = html_path.read_text()

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

On Windows platforms, Path.read_text() defaults to the system's active code page (e.g., CP1252). This will raise a UnicodeDecodeError when encountering non-ASCII characters like the em-dashes () present in index.html and site.json. Specifying encoding="utf-8" explicitly ensures cross-platform compatibility.

Suggested change
data = json.loads(data_path.read_text())
original = html_path.read_text()
data = json.loads(data_path.read_text(encoding="utf-8"))
original = html_path.read_text(encoding="utf-8")

Comment thread scripts/sync-site.py Outdated
return 0

if new_text != original:
html_path.write_text(new_text)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

Similarly, Path.write_text() should explicitly specify encoding="utf-8" to ensure the output file is written with UTF-8 encoding across all platforms.

Suggested change
html_path.write_text(new_text)
html_path.write_text(new_text, encoding="utf-8")

Comment thread scripts/test_sync_site.py Outdated
Comment on lines +63 to +64
data = json.loads((ss.REPO_ROOT / "data/site.json").read_text())
original = (ss.REPO_ROOT / "index.html").read_text()

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

Specify encoding="utf-8" here as well to prevent UnicodeDecodeError on Windows environments during test execution.

Suggested change
data = json.loads((ss.REPO_ROOT / "data/site.json").read_text())
original = (ss.REPO_ROOT / "index.html").read_text()
data = json.loads((ss.REPO_ROOT / "data/site.json").read_text(encoding="utf-8"))
original = (ss.REPO_ROOT / "index.html").read_text(encoding="utf-8")

@4444J99 4444J99 marked this pull request as ready for review May 26, 2026 18:07

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've left some high level feedback:

  • The INDENT = " " * 12 constant tightly couples render_organs to the current HTML formatting; consider deriving the indent from the matched <!-- organs:start --> line (e.g., via a capturing group on leading whitespace) to make the script resilient to future formatting changes.
  • The VALUE marker regex only allows [A-Za-z0-9_] in keys, which prevents using more descriptive marker names with hyphens or dots; you might want to broaden this character class if you expect more flexible key naming in data['values'].
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The `INDENT = " " * 12` constant tightly couples `render_organs` to the current HTML formatting; consider deriving the indent from the matched `<!-- organs:start -->` line (e.g., via a capturing group on leading whitespace) to make the script resilient to future formatting changes.
- The `VALUE` marker regex only allows `[A-Za-z0-9_]` in keys, which prevents using more descriptive marker names with hyphens or dots; you might want to broaden this character class if you expect more flexible key naming in `data['values']`.

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 006d117766

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread scripts/sync-site.py
Comment on lines +89 to +95
if args.check:
if new_text != original:
print("error: index.html is out of sync with data/site.json — "
"run `python3 scripts/sync-site.py`", file=sys.stderr)
return 1
print("index.html is in sync.")
return 0

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Fail check mode when required markers are missing

--check only compares new_text to original, so it returns success even when rendering emits warnings that the HTML no longer contains required markers. If index.html loses <!-- v:... --> or <!-- organs:start/end -->, no replacement occurs, new_text == original, and CI reports “in sync” while synchronization is actually broken. This creates a false negative that defeats the single-source-of-truth guardrail.

Useful? React with 👍 / 👎.

Comment thread .github/workflows/site-sync.yml Outdated
Comment on lines +30 to +31
- name: Run tests
run: python3 scripts/test_sync_site.py

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Run sync before strict sync assertion on push jobs

In the push/manual path, the workflow executes python3 scripts/test_sync_site.py before the sync step, but that test suite includes test_real_index_in_sync, which fails whenever data/site.json changed without an updated index.html. Because GitHub Actions stops on step failure, the later “Sync and commit” step never runs in the exact drift scenario it is meant to auto-fix.

Useful? React with 👍 / 👎.

Comment on lines +6 to +9
paths:
- "data/site.json"
- "scripts/sync-site.py"
- ".github/workflows/site-sync.yml"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Include index.html in push path triggers

The push trigger only watches data/site.json, scripts/sync-site.py, and the workflow file, so a direct push that edits only index.html will not run this workflow at all. That allows generated content drift on main with no check or auto-repair, which undermines the intended single-source-of-truth enforcement.

Useful? React with 👍 / 👎.

Comment thread scripts/sync-site.py Outdated

if new_text != original:
html_path.write_text(new_text)
print(f"updated {html_path.relative_to(REPO_ROOT)}")

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Avoid crashing when SITE_HTML is outside repo root

The script documents SITE_HTML as an override, but when a changed file is outside REPO_ROOT, html_path.relative_to(REPO_ROOT) raises ValueError and exits non-zero after writing. This breaks valid override usage and makes automation treat a successful sync as a failure.

Useful? React with 👍 / 👎.

Comment thread scripts/sync-site.py Outdated
if key not in values:
warnings.append(f"marker '{key}' has no entry in data['values']")
return m.group(0)
return f"{m.group(1)}{values[key]}{m.group(4)}"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Escape value marker content before injecting into HTML

The value replacement path writes values[key] directly into HTML comments without escaping, unlike the organ renderer which escapes both labels and URLs. If any data['values'] entry contains <, &, or quotes, the generated page can become malformed or inject unintended markup instead of plain text, which is a data-driven correctness and safety regression.

Useful? React with 👍 / 👎.

Read/write files as UTF-8 (index.html has em-dashes), and derive the nav
block's indent from the matched <!-- organs:start --> marker instead of a
hardcoded 12-space constant, so the script survives HTML reflows. Add tests
for explicit indent and marker-derived indent.

Addresses gemini-code-assist and sourcery-ai feedback on #3.

https://claude.ai/code/session_017iav9RLCuHkepAqnGWYMKo

4444J99 commented May 26, 2026

Copy link
Copy Markdown
Collaborator Author

Addressed the review feedback in aa20fb9:

  • UTF-8 explicitly on every read_text / write_text in sync-site.py and the test (index.html has em-dashes).
  • The nav block's indent is now derived from the matched <!-- organs:start --> marker rather than a hardcoded 12-space constant, so the script survives HTML reflows. Added explicit-indent and marker-derived-indent tests (9 passing); rendered index.html stays byte-identical.

On the VALUE marker-key character class: keeping it [A-Za-z0-9_] by design (snake_case identifiers); can broaden if needed.


Generated by Claude Code

--check now fails on warnings (deleted marker / orphan value), closing a
false-negative. HTML-escape value-marker content (parity with the organ
renderer). Use a repo-relative display helper so a SITE_HTML override outside
the repo root no longer crashes after writing. On the push/manual path, run
the sync before the in-sync guard test so the drift it repairs can't kill the
job; add index.html to the push triggers. Add a --check missing-marker test.

Addresses chatgpt-codex-connector review feedback on #3.

https://claude.ai/code/session_017iav9RLCuHkepAqnGWYMKo
@4444J99 4444J99 merged commit bfeadbd into main May 26, 2026
3 checks passed

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: a60b66ee08

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread scripts/test_sync_site.py
Comment on lines +97 to +98
out, _ = ss.render(original, data)
self.assertEqual(out, original, "index.html is out of sync with data/site.json")

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Assert sync warnings are empty in real-index guard

The test_real_index_in_sync guard only checks out == original and ignores warnings from render(). In the push/manual workflow path, this lets CI pass even if required markers were removed from index.html (for example <!-- v:synced --> or <!-- organs:start/end -->): sync-site.py warns but exits 0 in write mode, and this test still passes because no textual replacement occurs. That means the auto-repair job can report success while synchronization is actually broken on main.

Useful? React with 👍 / 👎.

Comment thread scripts/sync-site.py
if key not in seen:
warnings.append(f"value '{key}' has no matching marker in the HTML")

if "organs" in data:

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Treat missing organs data as an out-of-sync condition

render() only validates the nav block when the organs key exists, so if data/site.json drops or misspells organs, the existing HTML nav is left untouched and no warning is emitted. In --check mode this becomes a false “in sync” result even though the single source of truth for organ links is missing, which undermines the drift detection this script is intended to enforce.

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants