Skip to content

Import heron-polyfeed-reader M0–M6 and mint it from the RSR template - #3

Merged
hyperpolymath merged 18 commits into
mainfrom
claude/new-session-l2ejzl
Oct 27, 2026
Merged

hyperpolymath merged 18 commits into
mainfrom
claude/new-session-l2ejzl

Conversation

@hyperpolymath

Copy link
Copy Markdown
Owner

Summary

Brings the real project into this repository. The checkout held only the RSR template; the eleven SSH-signed milestone commits (M0–M6, a Zig 0.17 feed reader and site monitor) arrived as a git bundle. This PR merges that history (unrelated histories allowed, signatures preserved), mints the repository from the template with just repo-init, folds the handoff note into the roadmap, pins the toolchain and adds the project's own CI.

Three commits, each separable:

  1. Merge heron-polyfeed-reader M0-M6 history into the RSR template — LICENSE keeps the full MPL-2.0 text; .gitignore is the union with vendor/sqlite/ un-ignored.
  2. chore: mint heron-polyfeed-reader from the RSR template (just repo-init) — deed renamed, identity derived (uuid 92d77a2e-a0d2-5a05-bb0a-d95cfe1a8cf2), provenance pinned to template commit b012ce7. Clade and :position-type are left UNASSIGNED: the owner's act.
  3. feat: integrate heron into the estate: roadmap, docs, Zig CI, toolchain pin.

Changes

  • docs/status/ROADMAP.adoc absorbs HANDOFF.md (milestones, blockers, next actions, known gaps, decisions made without owner input); HANDOFF.md removed.
  • README, CONTRIBUTING, docs/{usage,architecture,contributing,troubleshooting}.adoc, CHANGELOG, examples/README.adoc written for heron.
  • Zig pinned to 0.17.0 exactly in mise.toml / mise.lock (official checksums; lock hand-edited, no mise in the session).
  • .github/workflows/zig-ci.yml: checksum-pinned Zig, zig fmt --check, unit tests, static musl release build, config smoke, both Containerfile stages; actions.lock entry added.
  • Justfile: build-release, test-smoke, clean wired to the Zig build.
  • Root allowlist: build.zig, build.zig.zon, Containerfile, .dockerignore, vendor/.
  • scripts/check-no-vlang.sh: exclude vendor/ (SQLite's iPrevLangid false-positives the case-insensitive pattern). Upstream candidate for standards.
  • zig fmt 0.17 applied to seven files (@intFromEnum → @backingInt, two literal re-wraps); no behaviour change.
  • Deed (ecosystem) :purpose and :not filled; CLAUDE.md, repository map and coaptation receipt regenerated (band green).
  • docs/governance/TEMPLATE-STANDARDS-AUDIT.adoc: restored the table cell the mint's OPENSSF line-delete removed. Upstream candidate for rsr-template-repo.

RSR Quality Checklist

Required

  • Tests pass (zig build test --summary all: 85/85; just test also runs the template's Idris2 seam, which needs idris2)
  • Code is formatted (zig fmt --check build.zig src clean)
  • Linter is clean (just lint)
  • No banned language patterns (no Python, Go, TypeScript, Deno or ReScript; JavaScript runs on Bun)
  • No unsafe blocks without // SAFETY: comments (Zig; the one -fno-sanitize=undefined is on the vendored C, documented in build.zig)
  • No banned functions
  • SPDX license headers present on all new/modified source files
  • No secrets, credentials, or .env files included

As Applicable

  • Repo deed (status) / (maturity) updated (incubating / experimental, set by the mint)
  • Repo deed (ecosystem) updated
  • Repo deed (meta) and/or docs/decisions/ updated (the handoff's decisions are listed in the roadmap as candidate ADRs; none written yet)
  • docs/status/ROADMAP.adoc updated
  • Documentation updated for user-facing changes
  • TOPOLOGY.md updated (none in this repo)
  • CHANGELOG updated
  • New dependencies reviewed for license compatibility (SQLite public domain; patched Zig std TLS client, MIT, src/vendor/NOTICE)
  • ABI/FFI changes validated (the template's src/interface/ seam is untouched; heron's own FFI is src/sqlite.zig)

Testing

On the merged tree with a checksum-verified Zig 0.17.0 (x86_64 Linux): zig build test --summary all 85/85 before and after the formatter; zig build -Doptimize=ReleaseSafe -Dtarget=x86_64-linux-musl; heron --config examples/heron.json check-config. Estate gates run locally and passing: check-root-shape (+ self-test), check-no-placeholders, check-no-md-in-docs, check-adoc-renders (157 files), check-lock-sync, check-action-pinning, check-no-vlang, check-invisible-characters, validate-template, validate-workflows, repo-map determinism, www suite, just verify, validate-state, validate-ai-install, validate-claude-md, validate-repo-map, coaptation verify.

Not green, and why: just validate → validate-rsr fails on the UNASSIGNED clade (deliberate until the owner chooses); just test / just build need idris2 for the template's ABI seam. The Containerfile stages were not built locally (no daemon); zig-ci.yml builds them here.

Known deviation: the three new commits are unsigned (the session had no signing key); the eleven imported commits keep their signatures.

Screenshots

Build Summary: 3/3 steps succeeded; 85/85 tests passed
test success
+- run test 85 pass (85 total) 1s MaxRSS:14M
ok: 3 source(s), 1 monitor(s); data dir /tmp/tmp.0uEqp1WTfF

Generated by Claude Code

claude added 14 commits October 13, 2026 11:43
…apter, fixtures

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018RAZ2eXR5QXneYQV8Pds98
…no busy loop

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018RAZ2eXR5QXneYQV8Pds98
…crash recovery

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018RAZ2eXR5QXneYQV8Pds98
…on, CLI

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018RAZ2eXR5QXneYQV8Pds98
…y, robots)

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018RAZ2eXR5QXneYQV8Pds98
…robe verified

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018RAZ2eXR5QXneYQV8Pds98
…n integration, e2e test

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018RAZ2eXR5QXneYQV8Pds98
…e-tested

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018RAZ2eXR5QXneYQV8Pds98
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018RAZ2eXR5QXneYQV8Pds98
Brings in the eleven signed milestone commits (bundle master 4e78d36,
"M0: scaffold ..." through "Add HANDOFF.md") alongside the template's
history. Unrelated histories are allowed so the milestone record and its
SSH signatures survive byte for byte.

Conflict resolution:
- LICENSE: keep the template's full MPL-2.0 text (the import carried a
  one-line pointer to the same licence).
- .gitignore: union. The template's /vendor/ rule is narrowed to
  /vendor/* with !/vendor/sqlite/ so the vendored SQLite amalgamation
  stays tracked and visible to the gates; zig-out/ and *.db* are added.

Nothing else is touched in this commit: the tree still carries the
template's identity and HANDOFF.md, both addressed in the next commits.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01J4QvDgkykTgAudYjoMWELf
`just repo-init` with answers piped on stdin (project and slug
heron-polyfeed-reader, owner hyperpolymath, author Jonathan D.A. Jewell
<j.d.a.jewell@open.ac.uk>, alt address from .mailmap, type binary,
service heron, port 8484, registry ghcr.io/hyperpolymath; ORCID,
organisation and OpenSSF id left blank rather than invented).

- Deed renamed to heron-polyfeed-reader_chora.deed; identity block
  replaced from build/templates/identity.deed.in. The uuid derives to
  92d77a2e-a0d2-5a05-bb0a-d95cfe1a8cf2 (uuid5 of
  github.com/hyperpolymath/heron-polyfeed-reader; not stored).
  (variant) and (provenance) record template commit b012ce7; the
  :template-branch is recorded as main (the branch the mint ran on sat
  at main's tip).
- Clade, :prefixed-name and ecosystem :position-type are UNASSIGNED:
  choosing them is the owner's act and `just validate-rsr` fails until
  it is done, deliberately.
- docs/ seeded from build/docs-seed; archetypes/, build/templates/ and
  build/docs-seed/ removed; instruction blocks stripped; self-name and
  dependabot passes; (rsr-profile) reset to declare nothing yet.
- HANDOFF.md and .machine_readable/ai/PLACEHOLDERS.adoc removed; the
  handoff's content moves to docs/status/ROADMAP.adoc, README.adoc and
  CONTRIBUTING.adoc in the next commit.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01J4QvDgkykTgAudYjoMWELf
…in pin

- docs/status/ROADMAP.adoc absorbs HANDOFF.md: milestones M0-M6 done,
  M7-M11 ahead, blockers, next actions, known gaps, and the design
  decisions made without owner input (each a candidate ADR).
- README.adoc, CONTRIBUTING.adoc, docs/{usage,architecture,contributing,
  troubleshooting}.adoc, CHANGELOG.adoc and examples/README.adoc written
  for heron (commands, config reference, layout, invariants, conventions).
- Zig pinned to 0.17.0 exactly in mise.toml and mise.lock (checksums are
  the official ones from ziglang.org/download/index.json; the lock was
  edited by hand because mise was not available; re-lock to confirm).
- .github/workflows/zig-ci.yml: checksum-pinned Zig (same digest as the
  Containerfile), fmt check, unit tests, static musl release build,
  config smoke, and both Containerfile stages; actions.lock entry added.
- Justfile: build-release, test-smoke and clean wired to the Zig build.
- .machine_readable/root-allow.txt: build.zig, build.zig.zon,
  Containerfile, .dockerignore, vendor/ allowed with reasons.
- scripts/check-no-vlang.sh: exclude vendor/ (SQLite's FTS3 identifier
  iPrevLangid matched the case-insensitive pattern; third-party code is
  untouchable, the pattern is canon). Candidate for standards upstream.
- zig fmt 0.17 applied to seven source files (@intFromEnum ->
  @backingInt, two literal re-wraps); 85/85 tests still pass.
- Deed: ecosystem :purpose and :not filled from the handoff's IS/IS-NOT.
- CLAUDE.md (arrival pack) and docs/architecture/REPOSITORY-MAP.adoc
  regenerated from the deed and the tree.
- docs/governance/TEMPLATE-STANDARDS-AUDIT.adoc: restore the table cell
  the mint's OPENSSF line-delete removed (a repo-init defect; candidate
  for rsr-template-repo upstream).
- .machine_readable/coaptation/receipts/latest.toml regenerated (`just coapt`,
  band green; it was amber for the template).
- .dockerignore: estate scaffolding kept out of the container build
  context.

Verified on the merged tree (Zig 0.17.0, x86_64 Linux): zig build test
85/85; zig fmt --check clean; ReleaseSafe musl build; heron check-config
on examples/heron.json; check-root-shape, check-no-placeholders,
check-no-md-in-docs, check-adoc-renders (157 files), check-lock-sync,
check-action-pinning, check-no-vlang, template-conformance (branch rule
aside), www suite, repo-map determinism: pass.
Not green here: just validate (clade UNASSIGNED, by design); just test
and just build (the template's Idris2 seam needs idris2, absent here;
the Zig steps pass).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01J4QvDgkykTgAudYjoMWELf
@coderabbitai

coderabbitai Bot commented Oct 27, 2026 •

Copy link
Copy Markdown

Important

Review skipped

Too many files!

This PR contains 216 files, which is 116 over the limit of 100.

To get a review, reduce the PR to 100 files or fewer by splitting it into smaller PRs or changing its base branch.

Upgrade to a paid plan to raise the limit.

This review couldn't start because sufficient usage credits or metered capacity aren't available. Add credits or update usage-based reviews in the billing tab, then retry.

Run configuration
Commits

Reviewing files that changed from the base of the PR and between b012ce7 and e7dcc61.

Files ignored due to path filters: 3
  • .github/workflows/actions.lock is excluded by !**/*.lock
  • archetypes/julia-library/actions.lock is excluded by !**/*.lock
  • mise.lock is excluded by !**/*.lock
Files selected for processing: 216
  • .cicd-hygiene-allow
  • .clinerules
  • .cursorrules
  • .devcontainer/Containerfile
  • .devcontainer/README.adoc
  • .devcontainer/devcontainer.json
  • .devcontainer/docker/devcontainer.json
  • .dockerignore
  • .editorconfig
  • .envrc
  • .gitattributes
  • .github/CODEOWNERS
  • .github/CODE_OF_CONDUCT.md
  • .github/CONTRIBUTING.md
  • .github/GOVERNANCE.md
  • .github/ISSUE_TEMPLATE/config.yml
  • .github/SECURITY.md
  • .github/SUPPORT.md
  • .github/copilot-instructions.md
  • .github/dependabot.yml
  • .github/hooks/validate-deed.sh
  • .github/settings.yml
  • .github/workflows/deed-validate.yml
  • .github/workflows/dogfood-gate.yml
  • .github/workflows/ossf-best-practices.yml
  • .github/workflows/sonarqube.yml
  • .github/workflows/zig-ci.yml
  • .gitignore
  • .machine_readable/ai/PLACEHOLDERS.adoc
  • .machine_readable/arrival-pack/README.adoc
  • .machine_readable/arrival-pack/claude-md.k9.ncl
  • .machine_readable/arrival-pack/extract.sh
  • .machine_readable/coaptation/README.adoc
  • .machine_readable/coaptation/coapt.k9.ncl
  • .machine_readable/coaptation/coapt.ncl
  • .machine_readable/coaptation/coapt.sh
  • .machine_readable/coaptation/extract-facts.sh
  • .machine_readable/coaptation/receipts/latest.toml
  • .machine_readable/coaptation/witness-map.ncl
  • .machine_readable/compliance/reuse/dep5
  • .machine_readable/configs/eclexiaiser.toml
  • .machine_readable/configs/git-cliff/cliff.toml
  • .machine_readable/configs/stapeln.toml
  • .machine_readable/contractiles/Justfile
  • .machine_readable/contractiles/README.adoc
  • .machine_readable/contractiles/adjust/adjust.k9.ncl
  • .machine_readable/contractiles/bust/bust.k9.ncl
  • .machine_readable/contractiles/dust/dust.k9.ncl
  • .machine_readable/contractiles/intend/intend.k9.ncl
  • .machine_readable/contractiles/must/must.k9.ncl
  • .machine_readable/contractiles/trust/trust.k9.ncl
  • .machine_readable/descriptiles/README.adoc
  • .machine_readable/descriptiles/anchors/README.adoc
  • .machine_readable/descriptiles/provisioning_praxis.deed
  • .machine_readable/root-allow.txt
  • .machine_readable/scripts/maintenance/maint-assault.sh
  • .machine_readable/self-validating/README.adoc
  • .machine_readable/self-validating/examples/ci-config.k9.ncl
  • .machine_readable/self-validating/examples/project-metadata.k9.ncl
  • .machine_readable/self-validating/examples/setup-repo.k9.ncl
  • .machine_readable/self-validating/methodology-guard.k9.ncl
  • .machine_readable/self-validating/template-hunt.k9.ncl
  • .machine_readable/self-validating/template-kennel.k9.ncl
  • .machine_readable/self-validating/template-yard.k9.ncl
  • .windsurfrules
  • CHANGELOG.adoc
  • CITATION.cff
  • CLAUDE.md
  • CONTRIBUTING.adoc
  • Containerfile
  • Justfile
  • README.adoc
  • archetypes/README.adoc
  • archetypes/julia-library/julia-library_praxis.deed
  • archetypes/julia-library/overlay/.github/workflows/julia-ci.yml.in
  • archetypes/julia-library/overlay/.github/workflows/julia-docs.yml.in
  • archetypes/julia-library/overlay/Project.toml.in
  • archetypes/julia-library/overlay/src/PACKAGE.jl.in
  • archetypes/julia-library/overlay/test/cases/smoke.jl
  • archetypes/julia-library/overlay/test/runtests.jl
  • build.zig
  • build.zig.zon
  • build/container/Containerfile
  • build/container/README.adoc
  • build/container/compose.yaml
  • build/container/entrypoint.sh
  • build/container/heron.json
  • build/container/stapeln/.gatekeeper.yaml
  • build/container/stapeln/compose.toml
  • build/container/stapeln/ct-build.sh
  • build/container/stapeln/deploy.k9.ncl
  • build/container/stapeln/manifest.toml
  • build/container/stapeln/rokur.toml
  • build/container/stapeln/vordr.toml
  • build/docs-seed/README.adoc
  • build/docs-seed/architecture.adoc
  • build/docs-seed/contributing.adoc
  • build/docs-seed/troubleshooting.adoc
  • build/docs-seed/usage.adoc
  • build/guix.scm
  • build/just/assess.just
  • build/just/container.just
  • build/just/groove.just
  • build/just/provision-lib.sh
  • build/just/repo-init.just
  • build/just/validate.just
  • build/manifest.scm
  • build/templates/ROADMAP.adoc.in
  • build/templates/identity.deed.in
  • docs/AFFIRMATION.adoc
  • docs/AI_INSTALLATION_GUIDE.adoc
  • docs/MAINTAINERS.adoc
  • docs/QUICKSTART.adoc
  • docs/RSR-PHILOSOPHY.adoc
  • docs/SETUP.adoc
  • docs/architecture.adoc
  • docs/architecture/REPOSITORY-MAP.adoc
  • docs/architecture/THREAT-MODEL.adoc
  • docs/attribution/CITATIONS.adoc
  • docs/contributing.adoc
  • docs/decisions/0000-template.adoc
  • docs/decisions/0001-adopt-rsr-standard.adoc
  • docs/decisions/0001-template.adoc
  • docs/developer/ABI-FFI-README.adoc
  • docs/governance/CRG-AUDIT-TEMPLATE.adoc
  • docs/governance/TEMPLATE-LINEAGE-AUDIT.adoc
  • docs/governance/TEMPLATE-STANDARDS-AUDIT.adoc
  • docs/onboarding/QUICKSTART-DEV.adoc
  • docs/onboarding/QUICKSTART-MAINTAINER.adoc
  • docs/onboarding/QUICKSTART-USER.adoc
  • docs/onboarding/llm-warmup-dev.adoc
  • docs/onboarding/llm-warmup-maintainer.adoc
  • docs/onboarding/llm-warmup-user.adoc
  • docs/practice/AI-CONVENTIONS.adoc
  • docs/practice/STATE-VISUALIZER-GUIDE.adoc
  • docs/practice/ci-cost-reduction.adoc
  • docs/proposals/root-cleanup.adoc
  • docs/reports/audit/pillar-audit-2026-04-15.adoc
  • docs/status/PROOF-NEEDS.adoc
  • docs/status/PROOF-STATUS.adoc
  • docs/status/READINESS.adoc
  • docs/status/ROADMAP.adoc
  • docs/status/TEST-NEEDS.adoc
  • docs/troubleshooting.adoc
  • docs/usage.adoc
  • examples/README.adoc
  • examples/heron.json
  • heron-polyfeed-reader_chora.deed
  • launcher.sh
  • mise.toml
  • scripts/campaigns/www-bundle.campaign
  • scripts/check-no-placeholders.sh
  • scripts/check-no-vlang.sh
  • scripts/deed-field.sh
  • scripts/migrate-wellknown-to-www.sh
  • scripts/sweep-wellknown.sh
  • scripts/validate-template.sh
  • sonar-project.properties
  • src/adapter.zig
  • src/app.zig
  • src/cli.zig
  • src/config.zig
  • src/daemon.zig
  • src/dates.zig
  • src/dedupe.zig
  • src/encoding.zig
  • src/engine.zig
  • src/feed.zig
  • src/feed_adapter.zig
  • src/http.zig
  • src/interface/ffi/src/main.zig
  • src/item.zig
  • src/localserver.zig
  • src/main.zig
  • src/monitor.zig
  • src/robots.zig
  • src/root.zig
  • src/scheduler.zig
  • src/sqlite.zig
  • src/store.zig
  • src/testdata/dedupe.rss
  • src/testdata/latin1-no-declaration.rss
  • src/testdata/malformed.rss
  • src/testdata/mixed-encoding.rss
  • src/testdata/odd-dates.rss
  • src/testdata/real/bbc.rss
  • src/testdata/real/kernel.rss
  • src/testdata/real/lwn.rss
  • src/testdata/real/rustblog.atom
  • src/testdata/real/slashdot.rdf
  • src/testdata/real/xkcd.atom
  • src/testdata/real/zig.rss
  • src/testdata/utf16le.atom
  • src/transport.zig
  • src/util.zig
  • src/vendor/NOTICE
  • src/vendor/tls_client.zig
  • src/web.zig
  • src/xml.zig
  • tests/aspect_tests.sh
  • tests/e2e.sh
  • tests/e2e/template_instantiation_test.sh
  • tests/workflows/mint_cleanup_test.sh
  • tests/workflows/template_conformance_test.sh
  • vendor/sqlite/sqlite3.c
  • vendor/sqlite/sqlite3.h
  • www/.well-known/aibdp.json
  • www/.well-known/humans.txt
  • www/.well-known/security.txt
  • www/README.adoc
  • www/dns/records/example.invalid.zone
  • www/policies/acceptable-use.adoc
  • www/policies/ai-use.adoc
  • www/policies/privacy.adoc
  • www/public/index.html
  • www/tests/check-migration.sh

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

…ap, HTTPS-only curl

Four CI reds on the first run of #3, each root-caused:

- Canon lockstep: the deed's (canon) clause pinned 2.1.2 with the old
  gates-sha256; canon.lock on standards main is 2.1.3 (PATCH: the law's
  files moved under 0-canon/, criteria unchanged, criteria-sha256 identical).
  Re-pinned :version and :gates-sha256 to the 2.1.3 values, as the check's
  own guidance says. The (provenance) clause keeps canon-version 2.1.2: it
  records what the repo was minted under, not what it tracks now.
- estate-audit / code-hygiene: TODO/FIXME/XXX markers in vendored
  third-party code (SQLite amalgamation, patched Zig std TLS client).
  Excluded by exact path in .cicd-hygiene-allow with the reason; heron's
  own source carries no markers.
- estate-rules: docs/architecture/REPOSITORY-MAP.adoc was generated while
  the index still listed the template files the mint removed; regenerated
  on the committed tree.
- SonarCloud S6506 on zig-ci.yml: curl now passes --proto '=https'
  --tlsv1.2 so a redirect can never downgrade the toolchain download
  (the SHA-256 check already caught substitution; this closes the
  transport side too).

CLAUDE.md and the coaptation receipt regenerated (deed changed; band green).
Local gates re-run: validate-claude-md, coaptation verify, validate-repo-map,
check-root-shape, check-lock-sync, check-action-pinning,
check-no-placeholders, check-adoc-renders, validate-workflows,
session contracts, validate-state: pass.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01J4QvDgkykTgAudYjoMWELf
@hyperpolymath
hyperpolymath marked this pull request as ready for review October 27, 2026 10:05
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 27, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-27T14:06:15.074941Z e7dcc61 New commits
ℹ️ 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" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@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: ca6156a0bf

ℹ️ 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 build/container/Containerfile Resolved
Comment thread Containerfile Resolved
Comment thread src/feed.zig Resolved
Comment thread src/web.zig Resolved
Comment thread src/monitor.zig Resolved
Comment thread src/web.zig Resolved
Comment thread src/store.zig Resolved
Comment thread src/config.zig Resolved
Comment thread src/localserver.zig Resolved
Comment thread src/feed.zig Resolved
Every finding was traced from a real input or caller before fixing; none was
far-fetched, so none was declined.

Soundness (panics/traps on untrusted or user input):
- feed.zig: an RSS/RDF <channel> without <title> no longer unwraps a null
  (daemon would have died on one malformed feed); test added.
- web.zig: page number clamped (max_page) so page * per cannot overflow u32
  in ReleaseSafe; e2e test requests /?page=4294967295.
- config.zig: cert_warn_days bounded 0..3650 before the u32 cast; two test
  cases added.

Correctness:
- xml.zig: deepText keeps mixed content in document order via a per-child
  text_pos marker ("Hello <b>big</b> world" -> "Hello big world"); test.
- config.zig: a present-but-mistyped boolean (web.enabled, allow_non_loopback,
  detect_changes, check_robots) is InvalidConfig instead of silently taking
  the default; three test cases.
- cli.zig: `heron fetch NAME` with an unknown name exits 2 with a message
  instead of a silent success.
- monitor.zig: check_robots=false clears a stale `blocked` flag (test); the
  cached robots.txt is no longer cut at 16 KiB below the 256 KiB fetch cap,
  so no Disallow past the cut is lost.
- web.zig: the bound address is accepted in Host alongside the loopback
  names (127.0.0.2, or an explicitly allowed non-loopback address); HEAD no
  longer marks an item read (e2e test).
- store.zig: a read-only instance refreshes its cached log length when the
  index points past it (web UI 500 on items the poller appended; test);
  ingest refuses a record longer than the replay limit instead of indexing
  something rebuild would later drop.
- feed.zig / feed_adapter.zig: relative Atom/RSS links are resolved against
  the feed URL (RFC 3986 §5, std.Uri.resolveInPlace); unit tests for the
  resolver and an adapter test with a relative href. xml:base is not
  consulted (documented).
- localserver.zig: SO_RCVTIMEO/SO_SNDTIMEO of 10 s per accepted connection,
  so an idle client cannot park the sequential accept loop. Verified by
  holding an idle socket: a second request was served after 9.6 s.

Containers:
- Containerfile: /data seeded in the image owned by UID 10001 so a fresh
  volume is writable by heron.
- build/container/Containerfile + entrypoint.sh: the template Tier-A image
  now builds heron (same pinned toolchain and digest as the root
  Containerfile; keep them in step), copies the static binary, defaults to
  `daemon`, and drops the curl /health check heron has no endpoint for.

Docs: usage.adoc (Host rule, link resolution, request deadline), CHANGELOG
Fixed section.

Verified: zig build test 89/89 (was 85), zig fmt --check clean, ReleaseSafe
musl build, check-config smoke, fetch-unknown-name exit code, and the local
estate gates (root shape, placeholders, adoc renders, repo map, CLAUDE.md,
coaptation, lock sync, no-vlang).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01J4QvDgkykTgAudYjoMWELf

@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: f14ffd305d

ℹ️ 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 build/container/compose.yaml Resolved
Comment thread build/container/compose.yaml Resolved
Comment thread src/store.zig Resolved
Comment thread src/feed_adapter.zig Resolved
Comment thread src/config.zig Resolved
Comment thread build/container/compose.yaml Resolved
Comment thread src/monitor.zig Resolved
Comment thread src/store.zig Resolved
Comment thread .dockerignore Resolved
Comment thread src/monitor.zig Resolved
Configuration (config.zig):
- getInt now rejects a present-but-non-integer value (quoted "9000" port,
  "60" timeout) as InvalidConfig instead of silently taking the default.
- Unknown keys are rejected at the top level, in `web`, and per source and
  monitor, which the documentation already promised; `"souces"` can no
  longer parse as "no sources". Six rejection cases added.

Store (store.zig):
- A log append whose SQLite indexing fails marks the store index_lagging;
  the next ingest replays from meta.indexed_offset first, so the durable
  records are never jumped over by the next batch's offset.
- plainText treats a bare "<" as text unless a tag opener follows, so
  decoded "2 < 3" keeps its text (test).

Monitor (monitor.zig):
- normalizeText decodes character references before hashing, so
  "A &amp; B" and "A &#38; B" no longer raise a CHANGED alert (test).
- With check_robots on, redirects are stepped through one hop at a time:
  each hop's path is checked against robots.txt and a hop to another origin
  is refused before that origin is fetched (RFC 9309 §2.3); at most five
  hops. Test: a 302 to another origin yields DOWN with the reason and the
  other origin is never requested.

Transport (transport.zig, http.zig):
- Response.final_url is populated after redirects; Response.location
  carries an unfollowed 3xx's Location. Tests on the local server.
- feed_adapter resolves relative links against the final URL (test).

Containers:
- .dockerignore no longer excludes build/, which hid the Tier-A entrypoint
  from its own COPY.
- build/container/compose.yaml: publishes the UI on 127.0.0.1 only, sets
  HERON_CONFIG/HERON_DATA, mounts build/container/heron.json (new, JCS
  canonical) read-only, drops the curl /health check heron cannot satisfy,
  and rokur depends on service_started.

Docs: usage.adoc (type and key strictness), CHANGELOG.

Verified: zig build test 90/90; zig fmt --check clean; ReleaseSafe musl build;
check-config passes on examples/heron.json and build/container/heron.json and
rejects a quoted port with "web.port must be an integer (unquoted)"; local
estate gates pass (root shape, adoc renders, repo map, CLAUDE.md, coaptation,
lock sync, no-vlang, invisible characters; compose.yaml parses).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01J4QvDgkykTgAudYjoMWELf

@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: 9929ea3566

ℹ️ 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 build/container/compose.yaml Resolved
Comment thread src/config.zig Resolved
Comment thread src/monitor.zig Resolved
Comment thread src/web.zig Resolved
Comment thread docs/usage.adoc Resolved
Comment thread src/store.zig Resolved
Comment thread src/cli.zig Resolved
Comment thread src/cli.zig Resolved
Comment thread src/cli.zig Resolved
Comment thread src/dates.zig Resolved
@hyperpolymath
hyperpolymath enabled auto-merge (squash) October 27, 2026 11:05
@coderabbitai

coderabbitai Bot commented Oct 27, 2026

Copy link
Copy Markdown

Add Carrot credits or activate Agent usage billing to use Autofix

@hyperpolymath
hyperpolymath enabled auto-merge (squash) October 27, 2026 11:26
Security:
- util.termSafe: C0 controls except TAB (so ESC, and with it every CSI/OSC
  sequence), DEL and the C1 controls U+0080..U+009F become U+FFFD. Applied to
  every network-derived string the CLI prints: list/search titles, show
  (title, url, source, body), and the last-error columns of `sources` and
  `monitors`. Unit test plus an end-to-end check on the release binary: a
  title carrying an OSC 52 clipboard write and a screen clear prints with
  zero ESC bytes.

Configuration:
- getStr rejects a present non-string value (data_dir, user_agent,
  web.bind, name, type, url) instead of silently using the default; four
  rejection cases.
- check-config fails on a source type no registered adapter serves
  ("fead"), instead of passing and failing on every poll.

Correctness:
- store.catchUp: when the log is shorter than meta.indexed_offset (restored
  or replaced), the derived items/FTS rows are cleared before reindexing, as
  rebuild does. Test: truncate the log to its first record, reopen, and the
  second record is neither listed nor searchable.
- web: pagination links keep `source` (and `all`), HTML-escaped; e2e check.
- dates: an hour of 24 is accepted only as 24:00:00; tests for 24:59:00,
  24:00:01 and the valid end-of-day form.
- cli fetch: the failure counter is usize (only zero/non-zero matters).
- compose.yaml: build context is ../.. (the repository root), so the
  Containerfile path and build.zig/src/vendor resolve.

Documentation (both errors were mine):
- usage.adoc: detect_changes and check_robots default to true, as the code
  does; check_robots describes what is actually alerted (BLOCKED when the
  path becomes disallowed; cross-origin redirects refused). README no longer
  claims robots.txt change alerts. Adding such an alert would be a new
  feature, not a fix, so the docs were brought to the code.

Verified: zig build test 92/92; zig fmt --check clean; ReleaseSafe musl build;
check-config on both example configs; the "fead" type and a non-string
data_dir are rejected with messages; local estate gates pass.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01J4QvDgkykTgAudYjoMWELf
@sonarqubecloud

Copy link
Copy Markdown

@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: e7dcc61970

ℹ️ 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 build/container/stapeln/compose.toml Resolved
Comment thread build/container/stapeln/compose.toml Resolved
Comment thread src/monitor.zig Resolved
Comment thread src/app.zig Resolved
Comment thread src/web.zig Resolved
Comment thread src/config.zig Resolved
Comment thread src/monitor.zig Resolved
Comment thread src/feed.zig Resolved
@hyperpolymath
hyperpolymath merged commit 44e6a11 into main Oct 27, 2026
40 checks passed
@hyperpolymath
hyperpolymath deleted the claude/new-session-l2ejzl branch October 27, 2026 14:23
hyperpolymath added a commit that referenced this pull request Nov 5, 2026
## Summary

Codex posted a fourth review round on e7dcc61 about 17 minutes before #3
squash-merged, so its 8 findings reached `main` without fixes. This PR
fixes all 8, each with a test. Every finding was traced to a real input
before fixing.

Reviewing this PR raised 13 more findings, from CodeRabbit and Codex. 11
are fixed. Two are left for the owner:
- **Hash-migration thread** (`src/monitor.zig`): still open; the
reasoning is on the thread.
- **SPDX header on `CHANGELOG.adoc`**: licence edits are owner-only
under the estate rules.

The PR also re-pins the deed to canon 2.1.4, released by `standards`
while this PR was open (`main` has the same stale pin). It brings
`docs/status/ROADMAP.adoc` up to date now that #3 has merged.

## Changes

**Web UI and configuration**

- **Use-after-free of configuration error text** (`src/app.zig`).
`config.Diagnostic` now keeps its text in its own fixed 512-byte buffer,
which truncates if needed. Before, the text lived in the parse arena,
which `App.load` freed on the error path before the CLI printed the
message. I reproduced this first: under the poisoning test allocator,
`main`'s code reads the message back as `UUUU…`.
- **Cross-site GET marked items read** (`src/web.zig`). `/item/N` now
marks the item read only when the browser's Fetch Metadata shows a
same-origin or user-typed navigation: `Sec-Fetch-Site: same-origin|none`
with `Sec-Fetch-Mode: navigate`. All other cases leave the item unread,
and the page then shows a POST **Mark read** button:
  - an `<img>` or link on another site
  - a same-site page on another local port
  - a client that sends no Fetch Metadata
- a prefetch or prerender, which gets a 503 so the real visit is a fresh
request

I chose this over POST-only read marks. Both close the hole, but this
one keeps "open = read" and ordinary links (open in new tab, copy link).
- **`web.bind` the listener cannot use** (`src/config.zig`).
`check-config` now rejects a host name such as `localhost`. It also
rejects a non-loopback address unless `allow_non_loopback` is set.
`isLoopback` moves to `config.zig` and classifies the parsed address,
not its spelling: 127.0.0.0/8, `::1` in any form, and
`::ffff:127.0.0.0/104`.

**Monitor and feed parsing**

- **`cert_warn_days: 0`** (`src/monitor.zig`, `src/cli.zig`,
`src/web.zig`). Zero turns the certificate check off as documented: no
probe and no alerts. The saved status is cleared, and both status views
hide it even before that poll (`monitor.shownCertNotAfter`).
- **RSS item URL** (`src/feed.zig`). The URL is chosen in this order:
1. The first RSS `<link>` with text, even when an `atom:link` comes
before it.
2. Otherwise an `atom:link` href, when its rel is absent or `alternate`
(compared case-insensitively, RFC 8288) and it is http(s) or relative.
3. Otherwise the guid, but only if it is a permalink; `rdf:about` counts
as one, per RSS 1.0.
- **`Price < 10` swallowed by change hashing** (`src/monitor.zig`). `<`
is treated as markup only when the next character could start a tag.
`tagOpener` moves to `util.zig`, and `store.plainText` uses the same
function.

**selur (Tier-C) stack** (`build/container/stapeln/compose.toml`)

- The file did not load at all. selur-compose parses with toml 0.8 (TOML
1.0), which rejected the template's multi-line inline tables. The
environment tables are now single-line, and a toml 0.8 parse passes.
- Sets `HERON_CONFIG` and `HERON_DATA`, replacing the template's unused
`APP_*` variables.
- Mounts `./../heron.json` read-only. selur's validator treats any
volume that does not start with `./` or `/` as a named volume.
- Publishes the port on `127.0.0.1` only, and drops the `curl /health`
check heron cannot satisfy.
- Documents that the rokur/svalinn gateway path cannot reach the UI as
configured. A fronting proxy must forward `Host` and a matching
`Origin`. The alternative is `just container-keep oci portable`.

**Repository**

- `heron-polyfeed-reader_chora.deed`: canon re-pinned to 2.1.4. Only the
version moved; the criteria and gates hashes are unchanged.
- `docs/usage.adoc`, `docs/architecture.adoc` and `CHANGELOG.adoc`
updated.
- `ROADMAP.adoc` gains:
  - a summary of the review rounds
  - the code-owner self-review merge blocker
  - where the signed milestone history lives (`refs/pull/3/head`)
- upstream candidates for `standards`, `rsr-template-repo` and
`metadatastician/selur`
  - a robots.txt-change alert as a feature idea

## RSR Quality Checklist

### Required

- [x] Tests pass: `zig build test` 95/95 (92 on `main`)
- [x] Code is formatted: `zig fmt --check` clean
- [x] Linter is clean (the Zig compiler rejects unused parameters and
locals, and the build is clean)
- [x] No banned language patterns
- [x] No `unsafe` blocks without `// SAFETY:` comments (not applicable
to Zig)
- [x] No banned functions
- [x] SPDX license headers present on all new/modified source files (no
new files)
- [x] No secrets, credentials, or `.env` files included

### As Applicable

- [ ] Repo deed `(status)` / `(maturity)` updated: not needed, the phase
is unchanged (the `(canon)` pin is updated)
- [x] `docs/status/ROADMAP.adoc` updated
- [x] Documentation updated for user-facing changes
- [x] `CHANGELOG` updated
- [ ] ABI/FFI changes validated: not applicable, no FFI changes

## Testing

- `zig build test --summary all`: 95/95 pass. New and extended tests
cover:
  - diagnostic lifetime through `App.load`
  - eight guid/link shapes, plus `webOrRelative`
- the web e2e test: cross-site, same-site, no Fetch Metadata, prerender,
same-origin and `none`
  - config rejections and loopback classification
  - `normalizeText` with `Price < 10`
  - `cert_warn_days: 0`, including cached status and the view helper
- ReleaseSafe build, then `heron check-config`:
  - Passes both example configs.
  - Accepts `0:0:0:0:0:0:0:1` and `::ffff:127.0.0.1`.
- Rejects `10.0.0.1`, `localhost` and a missing file, with intact
messages.
- `compose.toml` parses with the toml 0.8 crate that selur-compose uses.
- The canon lockstep comparison was re-run locally against the live
`canon.lock`. The CLAUDE.md and coaptation verifiers pass (nickel
1.17.0).
- CI on the head (c4c701a) is green across the board, including Canon
lockstep and estate-audit.
- Not verified: how selur resolves `./../heron.json` at run time. selur
is not available here.

## Screenshots

```
$ heron check-config --config bad.json      # {"web":{"bind":"localhost"}}
error: InvalidConfig: web.bind must be a numeric IP address such as 127.0.0.1 or ::1, not a host name
$ heron check-config --config /nonexistent.json
error: ConfigNotFound: cannot read config file /nonexistent.json
```

🤖 Generated with [Claude Code](https://claude.com/claude-code)

https://claude.ai/code/session_01J4QvDgkykTgAudYjoMWELf

---------

Co-authored-by: Claude <noreply@anthropic.com>
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