Skip to content

feat(blog): blog v7 contract and client (elected moderation, action fees, timelines, post tombstones) - #692

Merged
PastaPastaPasta merged 10 commits into
stagingfrom
feat/blog-v7
Oct 7, 2026
Merged

PastaPastaPasta merged 10 commits into
stagingfrom
feat/blog-v7

Conversation

@PastaPastaPasta

@PastaPastaPasta PastaPastaPasta commented Oct 7, 2026 •

Copy link
Copy Markdown
Owner

Summary

Blog v7: the mainnet-ready blog contract from the approved design, and the Yappr client for it. The client takes it on with NEXT_PUBLIC_BLOG_TOPOLOGY=v7. Nothing is registered or broadcast, and /devnet stays on v6 (.env.devnet is unchanged).

Contract (contracts/yappr-blog-contract.json, copied verbatim from the design)

  • Moderation: elected, one team per contract. Seats are contestable with a 30-day challenge cool-down, a 7-day join window, a 3-day vote window, maxAddedModerators: 10 and ownerProtected. The file's interim team is the contract owner. Registration picks the network's interim the way social v13 does (feat(contracts): social v13 (mainnet candidate) and the blocks contract #690, withInterim): devnet keeps the owner, and mainnet registers notYetUsable. validate-contract-offline --network mainnet shows the latter.
  • Fees: the comment tokenCost is removed. Creates now pay feeMultiplier action fees to the moderators: blog 80M, blogPost 80M, blogComment 16M.
  • New indexes:
    • blog.timeline [$createdAt] and blogPost.timeline [$createdAt]
    • blogComment.discussedRecent, a ranked window: 72h range, a new window every 24h
    • blogFollow.followersTrend (72h / 24h / 7-day ttl), replacing followersByDay
  • Merged count twins: comment counts move into postAndTime (rangeCountable) and follower counts into followers (rangeCountable, ranked at blogId).
  • Dropped: blogPost.ownerAndTime, blogComment.ownerAndTime, blogFollow.following and the all-time comment ranking.
  • Post tombstone:
    • deleted flag, and tombstoneIsBlank, which requires comments present-and-off and every content field absent
    • hasBody for live posts
    • deleted frozen once set
    • retractedWhen: {present: "deleted"}
    • slug, blogId and publishedAt survive
  • Field rules:
    • publishedNotAhead: publishedAt ≤ $updatedAt + 10 min, with $updatedAt now required
    • the slug pattern matches lib/utils/slug.ts
    • image URLs must be https:// or ipfs://
  • scripts/property-constraint-cases.mjs gains the 10 tombstone and publishedAt accept/refuse cases.

Client

  • Writes: blog, blogPost and blogComment creates carry the $actionFeeAgreement, the same way social post and reply writes do. The amounts come off the committed contract (lib/blog/blog-contract.ts) through declaredActionFeeFor, which state-transition-service uses for both the agreement and the unpriced-action guard. The YAPP comment payment and its UI now apply to v2–v6 only.
  • Discovery:
    • On v7, /blog gets a Blogs / Posts switch.
    • Blogs: Newest pages blog.timeline with Load more; Most followed; Trending (3 days) on followersTrend.
    • Posts: Latest posts pages blogPost.timeline; Most discussed (3 days) on discussedRecent.
    • Explore's blog tab reads the post timeline directly.
  • Reads:
    • getFollowedBlogs uses ownerAndBlog on v7.
    • Comment and follower counts read the merged indexes. The query shapes are unchanged: a pin is the prefix total, and grouped in counts still serve a whole list.
    • The unused owner-order post and comment reads are removed; their indexes are dropped on v7.
  • Delete: the author dashboard has a Delete action on v7, with a confirmation. It writes the tombstone through tombstoneDocument (new base option): {deleted: true, commentsEnabled: false} plus the kept fields.
  • Readers and tombstones:
    • Tombstones drop out of every listing, search, quote and notification, because isPublishedBlogPost now excludes them. Comment notifications on a deleted post are skipped too, and the owner's per-blog count leaves them out.
    • A tombstone's link and embed say the post was deleted.
    • The comment path refuses a tombstone before signing.
  • Field limits:
    • blogPostDate mirrors publishedNotAhead (10 minutes past $updatedAt) on posts that store $updatedAt (v7); older cuts date posts exactly as before.
    • A publish refused because the device clock runs more than 10 minutes ahead says so, rather than showing "Failed to publish".
    • Empty image URLs are left out instead of sent as ''.
    • On v7, an http:// image URL is refused before signing, with a message the user sees.
  • Paged lists: the blog and post discovery lists share useCursorList. A new sort restarts the list from page one, and a Load more still in flight when the sort changes is dropped instead of appended.
  • v1–v6 behavior is unchanged, with one write-shape exception: an empty image URL is now left out (or cleared on edit) instead of written as '', on every cut. Readers treat both the same.

Battery (scripts/verify-blog.mjs), self-test only

  • Priced creates carry the agreement. createBattery takes an agreementFor(sdk, docType) hook, and verify-blog passes seed-lib's feeAgreementFor with the blog schemas. attemptCreate sends the hand-built batch, and a case can name its own agreement or opt out.
  • The 40132/40133 matchers now live once, in social-battery-lib (verify-v8 and verify-v10 import them).
  • The YAPP pre-flight and accounting are removed.
  • Changed cases:
    • b3c: a comment with no agreement is refused (40132)
    • b9: a comment agreeing to the wrong amount is refused (40133)
    • counts and rankings now read the merged indexes and the 72h windows
  • New cases:
    • b22: the author's tombstone, using the shared refused shapes; checks that deleted and publishedAt are frozen and that the slug stays taken
    • b23: a banned author can retract its own post and do nothing else
    • b24: a comment on a tombstone is refused
  • selfTestV7 pins the v7 shape: elected moderation, no tokenCost, the fees, the timelines, the dropped indexes and retractedWhen.

Merged with #689 and #690

staging is merged in (no rebase). #689's getNewestBlogs gains the v7 branch: on v7 it returns the head of blog.timeline and is always complete. v1–v6 keep #689's capped, cached scan. Explore, search and discovery all go through it, and v7 discovery still pages getBlogTimelinePage. Discovery's "newest among the first N blogs" notice is kept on v1–v6.

Follow-ups (not in this PR)

  • lib/transition-agreements.ts now pulls the blog contract JSON (~15 KB) into the write path's bundle so the fee amounts cannot drift. The social contract JSONs are already bundled the same way. A generated constants module would trim it.
  • scripts/seed/non-social/blog.mjs still seeds the v6 shape (YAPP comments, commentCount). It needs the agreement plumbing before it can seed a v7 contract.
  • Registering v7, running the live battery, and cutting /devnet over to NEXT_PUBLIC_BLOG_TOPOLOGY=v7.

Test plan

  • node scripts/validate-contract-offline.mjs contracts/yappr-blog-contract.json --network mainnet --cost: parses under both validators; create size ~7,010 B signed; documentCreateCost (new index values) is blog 248.5M, blogPost 492.6M, blogComment 90.6M, blogFollow 72.6M
  • node scripts/validate-contract-offline.mjs --constraints: every case passes, including the 10 new blog v7 cases
  • node scripts/verify-blog.mjs --self-test, plus the storefront, pollr and v10 battery self-tests
  • npm run lint: eslint with the worktree's own config (the nested-worktree config clash is a known gotcha)
  • npm run test: 1980 tests after the staging merge; specs added for content-utils, blog-contract/fees, post/blog/follow/stats/comment services, the real tombstone payload and the notification filter
  • code review and simplification passes (findings applied in the last two commits)
  • npm run build
  • npm run lint:dead
  • npm run build:testing && npm run test:e2e (smoke): 24 passed, 4 skipped
  • Live battery against a registered v7 contract (needs registration, which is out of scope here)

🤖 Generated with Claude Code

PastaPastaPasta and others added 6 commits October 6, 2026 21:33
Elected per-contract moderation (seat contests, 30-day challenge
cool-down, 7-day join / 3-day vote windows, owner protected, interim
contract owner). The comment tokenCost is gone; blog, blogPost and
blogComment creates pay feeMultiplier action fees (80M / 80M / 16M).

New blog.timeline and blogPost.timeline [$createdAt] indexes, a ranked
72h discussedRecent window, and followersByDay replaced by a 72h
followersTrend. The count twins merge into postAndTime and followers;
blogPost.ownerAndTime, blogComment.ownerAndTime, blogFollow.following and
the all-time comment ranking are dropped.

Authors delete a post with a tombstone: deleted plus comments off, every
content field blank (tombstoneIsBlank), hasBody for live posts, deleted
frozen once set and retractedWhen so a barred author can still retract.
publishedAt may not run 10 minutes past a now-required $updatedAt; the
slug pattern matches lib/utils/slug.ts and image URLs are https or ipfs.

The constraint table gains the ten tombstone and publishedNotAhead cases.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Writes: blog, blogPost and blogComment creates carry the action fee
agreement, read off the committed contract (lib/blog/blog-contract.ts)
and attached through declaredActionFeeFor like social post/reply writes;
the YAPP comment payment and its UI apply to v2-v6 only.

Reads: discovery's Newest pages blog.timeline; a new Posts view lists the
latest posts across blogs (blogPost.timeline) and the most discussed
posts over the 72h discussedRecent window; Trending reads followersTrend
(3 days); a reader's follows ride ownerAndBlog; comment and follower
counts read the merged indexes with the same queries. Explore's blog tab
reads the post timeline. The unused owner-order post and comment reads,
whose indexes v7 drops, are gone.

Delete: the author dashboard deletes a post by writing the tombstone
(deleted, comments off, blogId/slug/publishedAt kept). Tombstones leave
every listing, their link and embed say the post was deleted, and the
comment path refuses them before signing.

Bounds: blogPostDate mirrors publishedNotAhead (10 minutes past
$updatedAt); empty image URLs are left out and v7 refuses non-https/ipfs
ones with a message before signing.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Every create of a priced doctype now carries the declared action fee
agreement (battery-lib attemptCreate takes an agreement and sends the
hand-built batch). The YAPP pre-flight and accounting are gone; b3c is a
comment with no agreement (40132) and b9 one agreeing to the wrong amount
(40133). Counts and rankings read the merged postAndTime / followers
indexes and the 72h discussedRecent / followersTrend windows.

New cases: b22 an author's tombstone (the shared refused shapes, frozen
deleted and publishedAt, the slug kept), b23 a banned author retracting
its own post and nothing else (retractedWhen), b24 a comment on a
tombstone. The self-test pins the v7 shape: elected moderation, no
tokenCost, the fees, the timelines, the dropped indexes, retractedWhen.

Self-test only; nothing was broadcast.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Fixes:
- A Load more still in flight when the sort changes no longer appends to
  the new list, and a failed sort switch no longer shows the previous
  list (useCursorList, shared by the blog and post discovery lists).
- Comment notifications skip posts their author has deleted.
- The owner's per-blog post count leaves deleted posts out.
- The 10-minute publishedAt allowance applies only to posts that store
  $updatedAt (v7), so v1-v6 dating is unchanged.
- A publish refused for a device clock more than 10 minutes ahead
  (publishedNotAhead) says so.
- The tombstone writer's drift log no longer names a social helper for a
  blog post.

Simplifications: PillTabs; enrichBlogPostsWithBlogNames; getBlogUrl;
imageUrlProblem; a POST_STATUS table on the dashboard; one newest-first
cursor page in BaseDocumentService and one getAllBlogs loop; the blog
fee and trend grids parsed by contract-topology's actionFeeOf and
timeRangeOf; blog-stats reuses windowClause; trendingBlogsCopy.

Tests cover the real tombstone payload (custom base, a draft, an
existing tombstone) and the notification filter.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
createBattery takes an agreementFor(sdk, docType) hook that every create
on the battery's contract uses unless the case names its own agreement
or opts out; verify-blog passes seed-lib's feeAgreementFor with the blog
schemas (actionFeeFor/feeAgreementFor take a schemas parameter) instead
of wrapping the battery. The 40132/40133 matchers live once in
social-battery-lib. verify-blog gains ensureFixtureBlog, a fixture-owned
replace and a module-level index helper, and reuses the constraint
table's drop. The "publishedAt ahead" constraint case moves to a day
ahead so a long live run still finds it ahead when it reaches b19.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Oct 7, 2026 •

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration
  • Configuration used: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: fbec38ad-ca83-40fe-8d52-dfef24cde313

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

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
  • Autopilot · 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.

@thepastaclaw

thepastaclaw commented Oct 7, 2026 •

Copy link
Copy Markdown
Collaborator

🔍 Review in progress — actively reviewing now (commit 6e199a0) · triage: critical · Phase 2 only (no Phase 1 for this repository)
████████░░░░░░░░░░░░ 38% · about 10 min left · running for 4 min
✅ triage → ⏭️ Phase 1 → ✅ Phase 2 → ✅ verify 2 → ⏳ fresh Phase 2 (0/1 lanes) → ▫️ publish
Estimated from recent reviews of this tier · updated 05:29 UTC · live progress

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Oct 7, 2026 •

Copy link
Copy Markdown

Deploying yappr with  Cloudflare Pages  Cloudflare Pages

Latest commit: 6e199a0
Status: ✅  Deploy successful!
Preview URL: https://6a1e77d2.yappr.pages.dev
Branch Preview URL: https://feat-blog-v7.yappr.pages.dev

View logs

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Oct 7, 2026 •

Copy link
Copy Markdown

Deploying yappr-v2 with  Cloudflare Pages  Cloudflare Pages

Latest commit: 6e199a0
Status: ✅  Deploy successful!
Preview URL: https://06916b16.yappr-v2.pages.dev
Branch Preview URL: https://feat-blog-v7.yappr-v2.pages.dev

View logs

Brings in #689 (getNewestBlogs with its capped, cached scan) and #690
(social v13 and per-network interim registration).

- blogService.getNewestBlogs gains the v7 branch: the head of
  blog.timeline, always complete. v1-v6 keep the capped scan. The old
  getAllBlogs is gone; explore, search and discovery all go through
  getNewestBlogs (v7 discovery still pages getBlogTimelinePage).
- Discovery's "newest among the first N blogs" notice survives on the
  shared cursor-list hook, as its `incomplete` flag.
- BaseDocumentService keeps both queryAll (#689) and the newest-first
  cursor page.
- Blog v7's file interim stays contractOwner, which #690's withInterim
  registers as notYetUsable on mainnet; the docs say so.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

@thepastaclaw thepastaclaw left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Final validation — Phase 2 only (no Phase 1 for this repository)

Verified the supplied findings against exact head 625daee and consolidated the duplicate reviewer reports into three in-scope blockers: two discovery regressions and a battery timeout-reconciliation failure. This was a static review; the supplied CI snapshot reports successful lint, type checks, unit/component tests, builds, and dead-code checks, while standard E2E was skipped and non-blocking devnet E2E remained in progress.

🔴 3 blocking

Review provenance

Source: reviewer 1: gpt-6.1-sol (agent: phase2-reviewer, role: general); reviewer 2: gpt-6-astra (agent: phase2-reviewer, role: general); final verifier: gpt-6.1-sol (agent: sol-verifier, role: final-verifier)

  • Triage: critical by gpt-6.1-sol (effort low) — This large, intricate diff changes consensus-enforced moderation, document constraints and fee allocation in contracts/yappr-blog-contract.json, and changes funds-payment agreements and pre-signing fee guards in lib/services/state-transition-service.ts.
  • Phase 1 reviewers: not run (disabled for this repository)
  • Fresh verifier: gpt-6.1-sol — final-verifier; agent sol-verifier
  • Phase 2 reviewers: gpt-6.1-sol — general (completed, effort xhigh); agent phase2-reviewer, gpt-6-astra — general (completed, effort xhigh); agent phase2-reviewer
  • Model comparison: every Phase-2 reviewer also ran on gpt-6-astra; the verifier weighed both sets without knowing which model wrote which
🤖 Prompt for all review comments with AI agents
These findings are from an automated code review. Verify each finding against the current code and only fix it if needed.

In `app/explore/page.tsx`:
- [BLOCKING] app/explore/page.tsx:117-120: Continue past filtered timeline pages in Explore
  `getLatestPosts({ limit: 20 })` limits the raw timeline documents before filtering drafts and tombstones, and returns `nextCursor` when more documents may remain. This branch discards that cursor and finishes loading immediately. If the newest 20 documents are drafts or tombstones, Explore displays “No blog posts yet” even when published articles exist on the next page, and provides no continuation control. The previous `getRecentPosts` path refilled past drafts; the new Posts discovery also reads beyond empty filtered pages and preserves its continuation. Follow the cursor to obtain public posts, or expose continuation and distinguish a filtered page from an exhausted timeline.

In `lib/blog/content-utils.ts`:
- [BLOCKING] lib/blog/content-utils.ts:343-344: Exclude posts whose parent blog has been removed
  The contract permits moderators to remove a `blog`, while its child posts remain valid through their `moderatedDocument` reference to the removal record. Those published posts can still appear in the new cross-blog timeline or discussed ranking, but `blogService.getMany` omits the removed parent. This helper nevertheless returns every original post, so Explore and Posts discovery render article cards whose links fail with “Blog not found”: `app/blog/page.tsx` requires the parent blog before fetching the post. The previous Explore path started from existing blogs and therefore excluded these orphaned articles. Filter against the resolved parent blogs before returning the hydrated posts, or implement an intentional readable route for posts with removed parents.

In `scripts/battery-lib.mjs`:
- [BLOCKING] scripts/battery-lib.mjs:317-321: Retain the derived document ID when an agreed create times out
  The new agreement branch calls `createWithAgreement`, which derives the exact document ID before broadcasting but returns it only after `broadcastAndWait` succeeds. If the transition lands and confirmation throws a 504, `attemptWrite` receives no result, leaving `storedById` dependent on `findRecentByValues`. Both query variants in that fallback require `$ownerId`, but v7 removes the owner indexes from `blogPost` and `blogComment`, so the fallback cannot find either document type. Successfully committed fixture writes are consequently reported as failures; a timed-out b1 post can abort the battery with “fixture posts unavailable.” Expose and retain the derived ID before waiting so reconciliation can fetch by ID even when confirmation throws, or reconcile through the surviving document-type-specific indexes.

Comment thread app/explore/page.tsx
Comment thread lib/blog/content-utils.ts Outdated
Comment thread scripts/battery-lib.mjs
PastaPastaPasta and others added 2 commits October 6, 2026 23:16
Explore's v7 blog tab read one timeline page and stopped, so a newest
page of drafts and tombstones showed "No blog posts yet" while published
posts sat on the next page. blogPostService.getLatestPublishedPosts reads
on (up to maxPages) until it has the posts it wants, and the Posts
discovery list uses it too.

enrichBlogPostsWithBlogNames now drops a post whose blog did not come
back: a moderator can remove a blog while its posts stay, and the post
page needs the blog, so the card only led to "Blog not found".

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
createWithAgreement derives the document id before broadcasting but only
returned it after broadcastAndWait. A create that landed while its wait
threw (the DAPI 504 quirk) left the battery reconciling by value through
an owner index, which blog v7's blogPost and blogComment no longer have,
so a committed fixture write read as a failure. createWithAgreement now
hands the id to onDerivedId before signing, and attemptCreate keeps it
for the by-id read back.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

@thepastaclaw thepastaclaw left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Re-review — Final validation — Phase 2 only (no Phase 1 for this repository)

Verified the supplied Phase-2 findings against head 6dea5f5: timeout ID preservation and removed-parent filtering are fixed, but Explore still presents a capped, filtered timeline as empty without continuation. Current CI passes lint, type checking, unit tests, browser-component tests, build, dead-code checking, App, and Engine checks; devnet E2E and Cloudflare deployment remain pending, and standard E2E is skipped. Verification was static; no local builds or tests were run.

🔴 1 blocking

1 carried-forward finding(s) already raised on this PR; not re-posting as new inline comments.

Review provenance

Source: reviewer 1: gpt-6.1-sol (agent: phase2-reviewer, role: general); final verifier: gpt-6.1-sol (agent: sol-verifier, role: final-verifier)

  • Triage: critical by gpt-6.1-sol (effort low) — This large, cross-cutting diff changes funds movement through moderator action fees in contracts/yappr-blog-contract.json and the corresponding fee agreements and guards in lib/services/state-transition-service.ts, alongside intricate moderation and tombstone behavior.
  • Phase 1 reviewers: not run (disabled for this repository)
  • Fresh verifier: gpt-6.1-sol — final-verifier; agent sol-verifier
  • Phase 2 reviewers: gpt-6.1-sol — general (completed, effort xhigh); agent phase2-reviewer
🤖 Prompt for all review comments with AI agents
These findings are from an automated code review. Verify each finding against the current code and only fix it if needed.

In `app/explore/page.tsx`:
- [BLOCKING] app/explore/page.tsx:119-121: Continue past filtered timeline pages in Explore
  (existing thread: https://github.com/PastaPastaPasta/yappr/pull/692#discussion_r4202933678)
  The bounded reader fixes an empty first page, but Explore still discards `nextCursor` when the scan reaches its cap. With 100 newest documents consisting of drafts or tombstones and a published article immediately behind them, this call reads five 20-document pages and returns no posts with a valid continuation cursor. Explore then finishes loading and renders “No blog posts yet” / “Be the first to publish an article!” without a way to continue. The page-cap regression spec confirms that the reader preserves the cursor at this boundary; Posts discovery already retains it, distinguishes a partial-empty result, and offers Load more. Keep the bounded scan, but preserve its continuation and distinguish a filtered result from an exhausted timeline, with a continuation control or a link to paged Posts discovery.

…rafts

Explore's v7 blog tab reads at most five timeline pages. When those held
only drafts, tombstones or posts of removed blogs while the timeline went
on, it showed "No blog posts yet". boundedPostListState tells that
"filtered, more exist" case apart from an exhausted timeline: Explore
then links to the paged Posts discovery (/blog?view=posts) instead of the
empty state, and adds the same "Browse all posts" link under a list that
has more after it. BlogDiscovery takes an initialView for the link.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@PastaPastaPasta
PastaPastaPasta merged commit aaa5b82 into staging Oct 7, 2026
13 checks passed
@PastaPastaPasta
PastaPastaPasta deleted the feat/blog-v7 branch October 7, 2026 05:30
PastaPastaPasta added a commit that referenced this pull request Oct 7, 2026
The shared fee-agreement plumbing (battery agreementFor hook, seed-lib
actionFeeFor/feeAgreementFor schemas parameter, the 40132/40133 matchers,
actionFeeOf) was byte-identical on both branches and now equals #692's.
declaredActionFeeFor routes all three priced contracts (social, blog v7,
storefront v6); the YAPP path pays only on blog v2-v6 and storefront v2-v5.
contracts/README.md keeps both cut paragraphs and the v7 blog / v6
storefront file entries, and the docs note that storefront v6 is registered
on sakura (EDr9McRV...). contracts/yappr-storefront-contract.json is
unchanged (sha256 c6c9c678...).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
PastaPastaPasta added a commit that referenced this pull request Oct 7, 2026
One conflict, scripts/seed/seed-lib.mjs actionFeeFor: #692 gave it a
`schemas` parameter for blog v7, and this branch had moved its body to
scripts/social-shapes.mjs actionFeeOf. Both kept: actionFeeFor(docType,
schemas = social) delegates to the one actionFeeOf, so blog, social and
the v13 report fee are read the same way.

The web report fee needed no change: #692's declaredActionFeeFor routes
a social-contract action to declaredActionFee, which reads v13's report
create fee, so the report write agrees to it through the shared helper.

Two suites that re-import modules per case (composite feed page, failed
notification sources) get a 20 s timeout: under the full parallel run
their first case's cold import passed 5 s.

Co-Authored-By: Claude Opus 5.5 (1M context) <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