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

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# https://editorconfig.org
root = true

[*]
charset = utf-8
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
indent_style = space
indent_size = 2

[*.md]
# Two trailing spaces are a hard line break in Markdown.
trim_trailing_whitespace = false

[*.py]
indent_size = 4

[{Gemfile.lock,*.bib}]
# Generated or exported by other tools: keep them byte-for-byte.
trim_trailing_whitespace = false
2 changes: 2 additions & 0 deletions .github/CODEOWNERS
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# Default owner for everything in the repository.
* @estcarisimo
96 changes: 96 additions & 0 deletions .github/REVIEW.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
# Code review brief

Every pull request to `main` is reviewed by an **independent reviewer with no context
from the authoring session** before it is merged. In practice that is a fresh AI
coding-agent session (currently a Claude Sonnet subagent) started for the review alone,
or a human. This file is the brief that session is given.

The loop: PR ready → fresh reviewer → **its full verdict is posted on the PR as a
comment** (by the author or the launching process: `gh pr comment <n> --body-file -`)
→ author fixes and pushes, rebutting anything not fixed in the same thread → **another**
fresh reviewer (never the same session), which reads the earlier verdicts and checks
that each finding was fixed or rebutted with evidence → repeat until `VERDICT: APPROVE`
on the final commit → merge. A review of an earlier commit does not count.

---

You are an independent code reviewer for the **CoNexDat website**, a static Jekyll 4
site (academicpages theme, jekyll-polyglot for ES/EN/FR, jekyll-scholar for BibTeX
publications) published at <https://conexdat.github.io>. You have no prior context on
this PR; that is deliberate. Be thorough and skeptical, as a strict maintainer would be:
concrete, evidence-based findings with file:line, and no praise.

## Setup

1. Resolve the branch from the PR number: `gh pr view <PR> --json headRefName -q .headRefName`.
Work in a throwaway checkout so the main checkout is untouched:
`git fetch origin && git worktree add --detach <scratch>/wt-<PR> origin/<branch>`, then
`cd` there. `<scratch>` is the scratch directory your environment assigned you, or
`mktemp -d`.
2. Read `AGENTS.md` (conventions, layout, "things that are easy to get wrong") and the PR
description **with its comments**: `gh pr view <PR> --comments`. Earlier review
rounds are there. For every finding of an earlier round, check that the current
commit fixes it or that the rebuttal holds; an unaddressed or wrongly rebutted
finding is itself a finding.
3. The diff under review is `git diff origin/main...HEAD` in your worktree.
4. Build and check, and report the results verbatim:
- `export PATH="/usr/local/opt/ruby@3.3/bin:$PATH"` (macOS/Homebrew; Ruby 3.3 only),
`bundle install`, then `JEKYLL_ENV=production bundle exec jekyll build`. The repeated
"Error reading file _layouts/single" warnings are a known, harmless polyglot quirk.
- The shell lines of every `run:` step of `.github/workflows/build.yml` against the
result (the topic-id check and the sanity checks).
- `lychee --config lychee.toml --offline --root-dir "$PWD/_site" --remap
'https://conexdat\.github\.io/(.*) file://'"$PWD"'/_site/$1' --exclude '/_site/LaNet-vi/'
'_site/**/*.html'` (internal links), and `curl -sIL` on every external URL the diff adds.
- `uvx pre-commit run --all-files` and, if workflows changed, `uvx zizmor .github/workflows/`.
5. For anything visual or interactive, build with `--config _config.yml,_config.dev.yml`,
serve `_site/` on **port 4000** (the dev config hard-codes that origin), and look at the
page in ES, EN and FR, light and dark mode, and at phone width (375 px).

## What to check

- Correctness: broken or wrong links (a 200 on a generic home page, a sign-in wall or a
parked domain is broken), Liquid errors, markup that polyglot rewrites (`href="/…"` gets
`/en/` or `/fr/`), JavaScript edge cases, behavior changes not described in the PR.
Verify claims in the PR description by running things, not by reading.
- Conventions from `AGENTS.md`: **ES/EN/FR in lock-step** for every content change;
**American English** in English text, comments, identifiers and docs (published paper
titles and proper names exempt); **no e-mail addresses** anywhere on the site; **no new
links into `cnet.fi.uba.ar`** except the pages AGENTS.md lists; new publications carry
`topics = {…}` with ids from `_data/publication_topics.yml`.
- Workflows: actions pinned to a full commit SHA with the version in a comment,
`persist-credentials: false`, least-privilege `permissions`, no untrusted input
interpolated into `run:`.
- Accessibility of new UI: keyboard operation, visible focus, contrast in both themes.
- Anything misleading in docs the PR adds or changes (numbers, commands, paths). Run the
commands.

Do not comment on style the hooks already enforce. Do not pad the review.

## Rules

- Read-only with respect to the branch: do not commit, push, or edit files outside your
worktree experiments. Remove the worktree when done (`git worktree remove --force`).
- Do not post to GitHub.

## Output (the final message, nothing else)

```
VERDICT: APPROVE | CHANGES REQUESTED
CHECKS: build=<pass/fail> ci-steps=<pass/fail> internal-links=<N errors> pre-commit=<pass/fail> zizmor=<pass/fail/n.a.>

FINDINGS (most severe first; omit if none)
1. [blocking|should-fix|nit] <file>:<line> — <one-sentence defect>
Evidence: <what you ran / observed>
Suggestion: <concrete fix>

EARLIER ROUNDS (omit on round 1)
- round <k> finding <i>: fixed in <commit> | rebuttal holds | NOT addressed (see finding <j>)

VERIFIED CLAIMS
- <claim from the PR description> — <how verified, result>

NOTES (optional, non-blocking)
```

`APPROVE` only if there are no blocking or should-fix findings.
25 changes: 18 additions & 7 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -1,18 +1,29 @@
version: 2
updates:
- package-ecosystem: github-actions
directory: "/"
schedule:
interval: weekly
cooldown:
default-days: 7 # let new releases settle before proposing them
labels: ["dependencies", "github_actions"]
groups:
actions:
patterns: ["*"]

- package-ecosystem: bundler
directory: "/"
schedule:
interval: monthly
interval: weekly
cooldown:
default-days: 7
open-pull-requests-limit: 5
labels: ["dependencies", "ruby"]
ignore:
# Pinned to 2.x on purpose: the academicpages partials do not compile under
# dart-sass (jekyll-sass-converter 3.x). See the Gemfile and AGENTS.md.
- dependency-name: jekyll-sass-converter
update-types: ["version-update:semver-major"]
groups:
jekyll:
patterns: ["*"]
- package-ecosystem: github-actions
directory: "/"
schedule:
interval: monthly
ruby-minor-and-patch:
update-types: ["minor", "patch"]
49 changes: 39 additions & 10 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
name: Build site

# Required check on every pull request (ruleset "Protect main"): build the site
# exactly as deploy.yml does, then check the output.
on:
pull_request:
workflow_dispatch:
Expand All @@ -16,26 +18,36 @@ jobs:
name: Build site
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Set up Ruby
uses: ruby/setup-ruby@v1
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
ruby-version: "3.3"
bundler-cache: true
persist-credentials: false

- name: Check publication topic ids
run: |
# Every id in a `topics = {...}` field must exist in
# _data/publication_topics.yml; an unknown id renders no chip silently.
fields=$(grep -ciE '^[[:space:]]*topics[[:space:]]*=' _bibliography/conexdat.bib || true)
if [ "$fields" -eq 0 ]; then
echo "::error::No topics fields found in _bibliography/conexdat.bib"; exit 1
fi
known=$(sed -n 's/^- id: *//p' _data/publication_topics.yml | sort -u)
used=$(grep -oE '^[[:space:]]*topics[[:space:]]*=[[:space:]]*\{[^}]*\}' _bibliography/conexdat.bib \
used=$(grep -oiE '^[[:space:]]*topics[[:space:]]*=[[:space:]]*\{[^}]*\}' _bibliography/conexdat.bib \
| sed -E 's/.*\{(.*)\}/\1/' | tr ',' '\n' | tr -d ' ' | sed '/^$/d' | sort -u)
matched=$(grep -ciE '^[[:space:]]*topics[[:space:]]*=[[:space:]]*\{[^}]*\}' _bibliography/conexdat.bib || true)
if [ "$matched" -ne "$fields" ]; then
echo "::error::$((fields - matched)) topics field(s) are not on one line as topics = {id1, id2}"; exit 1
fi
unknown=$(comm -13 <(echo "$known") <(echo "$used"))
if [ -n "$unknown" ]; then
echo "::error::Unknown publication topic id(s): $unknown"; exit 1
fi
echo "OK: $(echo "$used" | wc -l) topic ids used, all known"
echo "OK: $fields entries tagged, $(echo "$used" | wc -l) topic ids used, all known"

- name: Set up Ruby
uses: ruby/setup-ruby@14594264cd68ce8a2345dd349bc3d138a4ef85c8 # v1.327.0
with:
ruby-version: "3.3"
bundler-cache: true

- name: Build site (Jekyll + polyglot + scholar)
env:
Expand All @@ -57,12 +69,29 @@ jobs:
# entries (the filter splits on whitespace).
grep -q 'data-topic="latam"' _site/publications/index.html
grep -Eq 'data-topics="[a-z-]+ +[a-z-]+' _site/en/publications/index.html
# Group decision: no e-mail addresses anywhere on the site.
# Group decision: no e-mail addresses in any HTML page.
if grep -rl 'mailto:' _site --include='*.html'; then
echo "::error::mailto: link found (the site publishes no e-mail addresses)"; exit 1
fi
# Repository docs must not be published with the site.
for f in AGENTS.md CLAUDE.md CONTRIBUTING.md CODE_OF_CONDUCT.md SECURITY.md; do
for f in AGENTS.md CLAUDE.md CONTRIBUTING.md CODE_OF_CONDUCT.md SECURITY.md lychee.toml; do
test ! -e "_site/$f"
done
echo "OK: $(find _site -name '*.html' | wc -l) HTML files"

# Every internal link and asset must resolve inside the build. Absolute
# links to this site are mapped to the local files; external links are
# checked weekly by link-check.yml instead, so a PR never fails because
# some other server is down.
- name: Check internal links
uses: lycheeverse/lychee-action@e7477775783ea5526144ba13e8db5eec57747ce8 # v2.9.0
with:
args: >-
--config lychee.toml --offline
--root-dir ${{ github.workspace }}/_site
--remap 'https://conexdat\.github\.io/(.*) file://${{ github.workspace }}/_site/$1'
--remap 'https://conexdat\.github\.io$ file://${{ github.workspace }}/_site/'
--exclude '/_site/LaNet-vi/'
'_site/**/*.html'
fail: true
jobSummary: true
14 changes: 9 additions & 5 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,25 @@ on:
branches: [main]
workflow_dispatch:

permissions:
contents: write
permissions: {}

concurrency:
group: pages
cancel-in-progress: true

jobs:
build-deploy:
name: Build and deploy
runs-on: ubuntu-latest
permissions:
contents: write # push the built site to the gh-pages branch
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false

- name: Set up Ruby
uses: ruby/setup-ruby@v1
uses: ruby/setup-ruby@14594264cd68ce8a2345dd349bc3d138a4ef85c8 # v1.327.0
with:
ruby-version: "3.3"
bundler-cache: true
Expand All @@ -30,7 +34,7 @@ jobs:
run: bundle exec jekyll build --trace

- name: Deploy to gh-pages
uses: peaceiris/actions-gh-pages@v4
uses: peaceiris/actions-gh-pages@84c30a85c19949d7eee79c4ff27748b70285e453 # v4.1.0
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_branch: gh-pages
Expand Down
86 changes: 86 additions & 0 deletions .github/workflows/link-check.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
name: Link check

# Weekly check of every link on the site, internal and external. Broken links
# are reported in a single open issue labeled "broken-link", which is updated
# each week and closed automatically once everything passes again.
on:
schedule:
- cron: "41 7 * * 1" # Mondays 07:41 UTC
workflow_dispatch:

permissions: {}

concurrency:
group: link-check
cancel-in-progress: true

jobs:
links:
name: Check links
runs-on: ubuntu-latest
permissions:
contents: read
issues: write # open, update or close the broken-link report
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false

- name: Set up Ruby
uses: ruby/setup-ruby@14594264cd68ce8a2345dd349bc3d138a4ef85c8 # v1.327.0
with:
ruby-version: "3.3"
bundler-cache: true

- name: Build site
env:
JEKYLL_ENV: production
run: bundle exec jekyll build

- name: Check links
id: lychee
uses: lycheeverse/lychee-action@e7477775783ea5526144ba13e8db5eec57747ce8 # v2.9.0
with:
args: >-
--config lychee.toml
--root-dir ${{ github.workspace }}/_site
'_site/**/*.html'
output: lychee-report.md
format: markdown
fail: false
jobSummary: true

- name: Open, update or close the broken-link issue
env:
GH_TOKEN: ${{ github.token }}
EXIT_CODE: ${{ steps.lychee.outputs.exit_code }}
RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
run: |
existing=$(gh issue list --label broken-link --state open --json number --jq '.[0].number // empty')
if [ "$EXIT_CODE" != "0" ]; then
{
echo "The weekly link check found broken links on https://conexdat.github.io."
echo "Fix them in the source (see AGENTS.md: never link into cnet.fi.uba.ar;"
echo "prefer the new home of a project or a Wayback Machine snapshot)."
echo
echo "Run: $RUN_URL"
echo
# GitHub caps issue bodies at 65,536 characters.
if [ "$(wc -c < lychee-report.md)" -gt 60000 ]; then
head -c 60000 lychee-report.md
echo
echo
echo "_Report truncated; the full list is in the run's job summary._"
else
cat lychee-report.md
fi
} > issue-body.md
if [ -n "$existing" ]; then
gh issue edit "$existing" --body-file issue-body.md
gh issue comment "$existing" --body "Still failing as of $(date -u +%F). Report updated: $RUN_URL"
else
gh issue create --title "Broken links on the website" --label broken-link --body-file issue-body.md
fi
elif [ -n "$existing" ]; then
gh issue close "$existing" --comment "All links pass as of $(date -u +%F): $RUN_URL"
fi
Loading
Loading