INSTAGRAM-002E: source-only canonical social-post content and payload hash - #682
Open
rusty-sj wants to merge 1 commit into
Open
INSTAGRAM-002E: source-only canonical social-post content and payload hash#682rusty-sj wants to merge 1 commit into
rusty-sj wants to merge 1 commit into
Conversation
… hash
functions/socialPostContent.js — the caller-side computation the §8.7 reducer
and the INSTAGRAM-002B plan builder assume ("payloadHash is computed by the
caller"). Defines the officer-editable content record { contentSchemaVersion,
caption, mediaReference, altText, scheduledAtEpochSeconds, displayTimeZone,
disclosureRequired } with conservative bounds (caption <= 2200 with TAB/LF;
one-line alt text <= 1000; opaque media handle, never a URL; UTC epoch second in
[0, 4102444800]; IANA-style zone or UTC for display only). validateSocialPost-
Content is non-throwing in the §8.7 idiom (frozen projection or 'invalid_content').
computeSocialPostPayloadHash validates then returns a lowercase SHA-256 hex over
the fields in fixed order with length-framed, domain-separated encoding, and
throws SocialPostContentError on an invalid record so junk can never mint a
hash. The digest satisfies the reducer's opaque-identifier shape.
This is the one contract in the 002 set that legitimately holds caption/alt
text; it still carries no URL, recipient, member, or provider vocabulary.
Requires only node:crypto + node:util, imported by no runtime path, defines no
Rules or endpoint, reads no clock/randomness/network.
functions/socialPostContent.test.js — 43 tests: acceptance, ~25 rejection cases,
Proxy/accessor rejection, hash shape/determinism/per-field sensitivity/length-
framing, throw-on-invalid, source boundary.
SYSTEM_DESIGN.md §8.24.
Verification: npm --prefix functions run lint clean; test:run 70 suites / 7612
pass; npm run test:rules 5 suites / 418 pass.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GPs7CQHK2h8KqhgKKsXevv
✅ Deploy Preview for luminous-fox-7c393f ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Outcome
Add the source-only contract that defines a social post's officer-editable content and derives the one canonical hash that binds it — the caller-side
payloadHashcomputation the INSTAGRAM-002A reducer and INSTAGRAM-002B plan builder assume. Nothing new runs; no content is stored.Scope
main.functions/socialPostContent.js(new) —validateSocialPostContent(candidate)reads the exact revision-1 record{ contentSchemaVersion, caption, mediaReference, altText, scheduledAtEpochSeconds, displayTimeZone, disclosureRequired }and returns a frozen canonical projection or the fixed reasoninvalid_content, non-throwing in the §8.7 idiom.computeSocialPostPayloadHash(candidate)validates the same record and, only on success, returns a lowercase SHA-256 hex digest over the fields in fixed order with length-framed, domain-separated encoding (mprc-social-post-payload-sha256/mprc.social-post-payload.v1); on an invalid record it throwsSocialPostContentErrorso a bad record can never mint a hash. The digest satisfies the reducer's opaque-identifier shape, so it drops straight into a §8.7 command aspayloadHashand a record asapprovedHash.1..2200chars, TAB/LF allowed, other C0/DEL/C1 controls rejected;mediaReferencean opaque bounded url-safe handle (never a URL);altText1..1000, one line;scheduledAtEpochSecondsa safe integer in[0, 4102444800](UTC, canonical);displayTimeZonean IANA-style zone name orUTC, presentational only;disclosureRequiredboolean.functions/socialPostContent.test.js(new) — 43 tests: acceptance (incl. TAB/LF in caption,UTCand three-segment zones, inclusive schedule bounds), ~25 rejection cases,Proxy/accessor rejection without trap or getter invocation, hash shape (^[0-9a-f]{64}$and the reducer's opaque-id pattern), determinism, per-field digest sensitivity, a field-boundary collision guard, throw-on-invalid with no input echo, and a source-boundary battery (requires onlynode:crypto+node:util; not imported byindex.js; no clock/randomness/network/provider surface; names no concrete provider; digest is domain-separated).SYSTEM_DESIGN.md§8.24.index.jswiring, no migration. This is the one contract in the 002 set that legitimately holds a caption and alt text; it still carries no URL, recipient, member, or provider vocabulary. It computes no schedule-to-wall-clock conversion, reads no clock, and hashes only a validated record.Officer handoff
NOT AVAILABLE YETand are owner decisions under INSTAGRAM-002 — Add an approval-gated social-post state and audit model #92.Proof by surface
npm --prefix functions run lint— clean.npm --prefix functions run test:run -- --runInBand— 70 suites / 7612 pass (2 unrelated emulator suites skipped).npm run test:rules— 5 suites / 418 pass (unchanged; this slice touches no Rules).runmprc.comverified: not relevant.Safety review
NOT AVAILABLE YET.Owner decisions still needed (do not block this slice)