Repository navigation
Import heron-polyfeed-reader M0–M6 and mint it from the RSR template - #3
Conversation
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018RAZ2eXR5QXneYQV8Pds98
…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
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
|
Important Review skippedToo 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.
|
…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
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
There was a problem hiding this comment.
💡 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".
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
There was a problem hiding this comment.
💡 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".
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 & B" and "A & 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
There was a problem hiding this comment.
💡 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".
|
Add Carrot credits or activate Agent usage billing to use Autofix |
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
|
There was a problem hiding this comment.
💡 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".
## 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>



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:
Merge heron-polyfeed-reader M0-M6 history into the RSR template— LICENSE keeps the full MPL-2.0 text;.gitignoreis the union withvendor/sqlite/un-ignored.chore: mint heron-polyfeed-reader from the RSR template (just repo-init)— deed renamed, identity derived (uuid92d77a2e-a0d2-5a05-bb0a-d95cfe1a8cf2), provenance pinned to template commit b012ce7. Clade and:position-typeare left UNASSIGNED: the owner's act.feat: integrate heron into the estate: roadmap, docs, Zig CI, toolchain pin.Changes
docs/status/ROADMAP.adocabsorbsHANDOFF.md(milestones, blockers, next actions, known gaps, decisions made without owner input);HANDOFF.mdremoved.docs/{usage,architecture,contributing,troubleshooting}.adoc, CHANGELOG,examples/README.adocwritten for heron.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, bothContainerfilestages;actions.lockentry added.Justfile:build-release,test-smoke,cleanwired to the Zig build.build.zig,build.zig.zon,Containerfile,.dockerignore,vendor/.scripts/check-no-vlang.sh: excludevendor/(SQLite'siPrevLangidfalse-positives the case-insensitive pattern). Upstream candidate forstandards.zig fmt0.17 applied to seven files (@intFromEnum→@backingInt, two literal re-wraps); no behaviour change.(ecosystem):purposeand:notfilled; 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 forrsr-template-repo.RSR Quality Checklist
Required
zig build test --summary all: 85/85;just testalso runs the template's Idris2 seam, which needsidris2)zig fmt --check build.zig srcclean)just lint)unsafeblocks without// SAFETY:comments (Zig; the one-fno-sanitize=undefinedis on the vendored C, documented inbuild.zig).envfiles includedAs Applicable
(status)/(maturity)updated (incubating / experimental, set by the mint)(ecosystem)updated(meta)and/ordocs/decisions/updated (the handoff's decisions are listed in the roadmap as candidate ADRs; none written yet)docs/status/ROADMAP.adocupdatedTOPOLOGY.mdupdated (none in this repo)CHANGELOGupdatedsrc/vendor/NOTICE)src/interface/seam is untouched; heron's own FFI issrc/sqlite.zig)Testing
On the merged tree with a checksum-verified Zig 0.17.0 (x86_64 Linux):
zig build test --summary all85/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-rsrfails on the UNASSIGNED clade (deliberate until the owner chooses);just test/just buildneedidris2for the template's ABI seam. TheContainerfilestages were not built locally (no daemon);zig-ci.ymlbuilds them here.Known deviation: the three new commits are unsigned (the session had no signing key); the eleven imported commits keep their signatures.
Screenshots
Generated by Claude Code