Repository navigation
feat: run jobs from the Haskell binding #33
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -2,8 +2,8 @@ | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| -- | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| -- "EventSorcery.Engine" re-exports the consumer-facing half of this module. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| -- The call marshalling and the errors every call can answer with stay here so | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| -- the stream feature can issue engine calls without republishing the ABI | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| -- plumbing to consumers. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| -- the stream and job features can issue engine calls without republishing the | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| -- ABI plumbing to consumers. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| module EventSorcery.Engine.Internal ( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| AbiVersionDetail (..), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| AggregateId (..), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -12,12 +12,16 @@ module EventSorcery.Engine.Internal ( | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ConflictDetail (..), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| EngineError (..), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| EngineErrorDecodeDetail (..), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| JobId (..), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| JobRefusal (..), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| JobRefusalDetail (..), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| OpenOptions (..), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| PageAdvanceDetail (..), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ResourceLimitDetail (..), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Store, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| abiVersion, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| callWithOutput, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| callWithTag, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| callWithoutOutput, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| checkAbiVersion, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| closeStore, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -62,7 +66,7 @@ import Data.ByteString.Lazy qualified as LazyByteString | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import Data.ByteString.Unsafe (unsafeUseAsCStringLen) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import Data.Text (Text) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import Data.Text qualified as Text | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import Data.Word (Word32, Word64) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import Data.Word (Word32, Word64, Word8) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import EventSorcery.Engine.Acquisition ( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| StoreAcquisition (..), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| acquireStore, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -136,7 +140,7 @@ supportedAbiMajor = 0 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| -- | The oldest ABI minor version whose calls this binding can make. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| minimumAbiMinor :: Word32 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| minimumAbiMinor = 2 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| minimumAbiMinor = 3 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| -- | Decides whether a packed engine ABI version can serve this binding. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -195,6 +199,36 @@ data ConflictDetail = ConflictDetail | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| deriving stock (Eq, Show) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| -- | Identity of a durable job -- a ULID minted when the job is enqueued. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| newtype JobId = JobId Text | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| deriving newtype (Eq, Show) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| -- | Why one job refused the request made of it. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| -- | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| -- The engine renders each reason as fixed ABI text, so the reason is a closed | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| -- vocabulary rather than prose: a refusal is terminal for the job it names, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| -- and a caller decides what to do next by matching on it. A newer engine may | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| -- add a leaf this binding has no constructor for, which keeps its rendered | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| -- identity the way an unmodelled error class keeps its numeric one. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| data JobRefusal | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| = AttemptExhausted | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| | InvalidClaimPolicy | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| | SettlementRefused | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| | PayloadNotOpaqueBytes | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| | PayloadByteOutOfRange | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| | PayloadAboveAbiLimit | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| | UnrecognizedRefusal Text | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| deriving stock (Eq, Show) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| data JobRefusalDetail = JobRefusalDetail | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { jobId :: JobId | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| , refusal :: JobRefusal | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| deriving stock (Eq, Show) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| data ResourceLimitDetail = ResourceLimitDetail | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { resource :: Text | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| , observed :: Word64 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -239,12 +273,14 @@ data BindingFault | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| | PageDidNotAdvance PageAdvanceDetail | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| | UndecodableEngineError EngineErrorDecodeDetail | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| | UndecodableResponse Text | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| | UnknownResultTag Word8 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| deriving stock (Eq, Show) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| data EngineError | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| = MalformedInput | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| | OptimisticConflict ConflictDetail | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| | JobRefused JobRefusalDetail | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| | StorageFailure Text | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| | InvalidState Text | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| | ResourceLimitExceeded ResourceLimitDetail | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -349,6 +385,24 @@ callWithOutput call = | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| useOutput `finally` esBufFree output | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| -- | Reads a call that answers with a single byte tag rather than a buffer. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| -- | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| -- The tag only means anything once the call has succeeded, and the engine | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| -- writes it while it still owns the cell. The sentinel poked in first is | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| -- outside the tags the ABI defines, so a call that answered without writing | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| -- one is reported as an unknown tag instead of being read as the zero tag. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| callWithTag | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| :: (Ptr Word8 -> Ptr EsBuf -> IO CInt) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| -> IO (Either EngineError Word8) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| callWithTag call = | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| alloca $ \output -> do | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| poke output unwrittenTag | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| called <- callWithoutOutput (call output) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| case called of | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Left engineError -> pure (Left engineError) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Right () -> Right <$> peek output | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+388
to
+405
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win Detect the unwritten sentinel inside The comment states that a call which wrote no tag is reported as an unknown tag. Reject the sentinel where it is poked, so the invariant is local. ♻️ Proposed change callWithTag call =
alloca $ \output -> do
poke output unwrittenTag
called <- callWithoutOutput (call output)
case called of
Left engineError -> pure (Left engineError)
- Right () -> Right <$> peek output
+ Right () -> do
+ tag <- peek output
+ pure
+ if tag == unwrittenTag
+ then Left (BindingProtocolError (UnknownResultTag tag))
+ else Right tag📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| decodeResponse | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| :: (ByteString -> Either String value) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| -> ByteString | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -425,6 +479,11 @@ decodeEngineErrorDetail 2 = do | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ( OptimisticConflict | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| (ConflictDetail {aggregateType, aggregateId, expectedVersion, actualVersion}) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| decodeEngineErrorDetail 3 = do | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| expectListLength 2 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| jobId <- JobId <$> decodeString | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| refusal <- decodeJobRefusal | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| pure (JobRefused (JobRefusalDetail {jobId, refusal})) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| decodeEngineErrorDetail 4 = StorageFailure <$> decodeString | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| decodeEngineErrorDetail 5 = InvalidState <$> decodeString | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| decodeEngineErrorDetail 6 = do | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -447,6 +506,20 @@ decodeEngineErrorDetail code = do | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| pure (UnknownEngineError code) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| -- | Reads the refusal reason the engine renders as fixed ABI text. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| decodeJobRefusal :: Decoder s JobRefusal | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| decodeJobRefusal = do | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| reason <- decodeString | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| pure case reason of | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "job attempt counter exhausted" -> AttemptExhausted | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "invalid job claim policy" -> InvalidClaimPolicy | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "job aggregate refused the settlement" -> SettlementRefused | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "claimed job payload is not opaque bytes" -> PayloadNotOpaqueBytes | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "claimed job payload contains an invalid byte" -> PayloadByteOutOfRange | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "claimed job payload exceeds the ABI payload limit" -> PayloadAboveAbiLimit | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| unmodelled -> UnrecognizedRefusal unmodelled | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+509
to
+522
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick win 🧩 Analysis chain🏁 Script executed: #!/bin/bash
# Compare the binding's refusal literals with the engine-side rendered text.
rg -n -C2 'job attempt counter exhausted|invalid job claim policy|job aggregate refused the settlement|claimed job payload' --glob '!bindings/haskell/**'Repository: dataclique/event-sorcery Length of output: 162 🏁 Script executed: printf '%s\n' '--- SPEC.md ---'
sed -n '1,220p' SPEC.md
printf '%s\n' '--- docs/domain.md ---'
sed -n '1,220p' docs/domain.md
printf '%s\n' '--- candidate files ---'
git ls-files | rg '(^|/)(SPEC\.md|docs/domain\.md|.*(Engine|WireSpec|Refusal|Error).*)$' | head -200
printf '%s\n' '--- relevant symbols and literals ---'
rg -n -C3 'decodeJobRefusal|JobRefusal|AttemptExhausted|SettlementRefused|UnrecognizedRefusal|job attempt counter exhausted|invalid job claim policy|job aggregate refused the settlement|claimed job payload' --glob '!*.env*' --glob '!credentials.json' --glob '!*.key' --glob '!*.pem' --glob '!*.p12' --glob '!*.pfx'Repository: dataclique/event-sorcery Length of output: 21077 🏁 Script executed: printf '%s\n' '--- Internal.hs outline and size ---'
wc -l bindings/haskell/src/EventSorcery/Engine/Internal.hs
ast-grep outline bindings/haskell/src/EventSorcery/Engine/Internal.hs | sed -n '1,220p'
printf '%s\n' '--- refusal decoder and model ---'
sed -n '180,245p' bindings/haskell/src/EventSorcery/Engine/Internal.hs
sed -n '480,535p' bindings/haskell/src/EventSorcery/Engine/Internal.hs
printf '%s\n' '--- Haskell refusal references ---'
rg -n -C4 'JobRefusal|AttemptExhausted|SettlementRefused|UnrecognizedRefusal|decodeJobRefusal|job attempt counter|invalid job claim|refused the settlement|payload is not opaque|invalid byte|ABI payload' bindings/haskell
printf '%s\n' '--- refusal references outside Haskell binding ---'
rg -n -C4 'AttemptExhausted|SettlementRefused|PayloadNotOpaqueBytes|PayloadByteOutOfRange|PayloadAboveAbiLimit|UnrecognizedRefusal|job attempt counter|invalid job claim|refused the settlement|payload is not opaque|invalid byte|ABI payload' --glob '!bindings/haskell/**' --glob '!*.env*' --glob '!credentials.json' --glob '!*.key' --glob '!*.pem' --glob '!*.p12' --glob '!*.pfx'Repository: dataclique/event-sorcery Length of output: 15527 🏁 Script executed: printf '%s\n' '--- SPEC ABI/error sections ---'
rg -n -C5 'refusal|JobRefused|error|ABI text|wire|numeric|claim policy|payload' SPEC.md docs adrs bindings/haskell --glob '*.md' --glob '*.hs'
printf '%s\n' '--- Rust and C ABI files ---'
git ls-files | rg '(^|/)(src|crates|bindings)/.*\.(rs|h|c|cc|cpp)$' | head -300
printf '%s\n' '--- engine error encoders and refusal strings ---'
rg -n -C5 'JobRefused|job_refused|JobRefusal|AttemptExhausted|InvalidClaimPolicy|SettlementRefused|PayloadNotOpaqueBytes|PayloadByteOutOfRange|PayloadAboveAbiLimit|attempt counter exhausted|invalid job claim policy|refused the settlement|payload exceeds|opaque bytes|invalid byte' crates src bindings --glob '*.!env*' --glob '!*.key' --glob '!*.pem' --glob '!*.p12' --glob '!*.pfx' 2>/dev/null || true
printf '%s\n' '--- WireSpec relevant regions ---'
sed -n '80,140p' bindings/haskell/test/WireSpec.hs
sed -n '620,675p' bindings/haskell/test/WireSpec.hsRepository: dataclique/event-sorcery Length of output: 50383 🏁 Script executed: printf '%s\n' '--- SPEC error identity ---'
sed -n '298,326p' SPEC.md
printf '%s\n' '--- exact refusal literals in tracked files ---'
git grep -n -C2 -E 'job attempt counter exhausted|invalid job claim policy|job aggregate refused the settlement|claimed job payload is not opaque bytes|claimed job payload contains an invalid byte|claimed job payload exceeds the ABI payload limit' -- ':!bindings/haskell/**' || true
printf '%s\n' '--- refusal/error identifiers in tracked files ---'
git grep -n -C3 -E 'JobRefused|JobRefusal|AttemptExhausted|InvalidClaimPolicy|SettlementRefused|PayloadNotOpaqueBytes|PayloadByteOutOfRange|PayloadAboveAbiLimit|UnknownEngineError|RESOURCE_LIMIT|MALFORMED_INPUT' -- '*.rs' '*.hs' '*.md' '*.h' | head -500
printf '%s\n' '--- WireSpec fixtures ---'
sed -n '100,135p' bindings/haskell/test/WireSpec.hs
sed -n '630,675p' bindings/haskell/test/WireSpec.hs
printf '%s\n' '--- all ABI/error-related Rust filenames ---'
git ls-files '*.rs' | rg 'abi|ffi|engine|job|error|wire|codec|cbor' | head -250Repository: dataclique/event-sorcery Length of output: 41639 🏁 Script executed: printf '%s\n' '--- refusal encoder and Rust tests ---'
sed -n '1245,1325p' crates/event-sorcery-ffi/src/lib.rs
sed -n '1748,1812p' crates/event-sorcery-ffi/src/lib.rs
sed -n '2160,2185p' crates/event-sorcery-ffi/src/lib.rs
sed -n '4120,4300p' crates/event-sorcery-ffi/src/lib.rs
printf '%s\n' '--- refusal tests and conformance references ---'
git grep -n -C5 -E 'PayloadNotOpaqueBytes|PayloadByteOutOfRange|PayloadAboveAbiLimit|AttemptExhausted|SettlementRefused|InvalidClaimPolicy|job-refusal|JOB_REFUSAL|fixed ABI|canonical detail|conformance corpus' -- crates bindings SPEC.md docs adrs | head -700
printf '%s\n' '--- encoded fixture declarations ---'
rg -n -C3 'jobRefusal|unmodelledRefusal|invalid job claim policy|reason' bindings/haskell/test/WireSpec.hsRepository: dataclique/event-sorcery Length of output: 43062 🏁 Script executed: python3 - <<'PY'
from pathlib import Path
import re
rust = Path("crates/event-sorcery-ffi/src/lib.rs").read_text()
hs = Path("bindings/haskell/src/EventSorcery/Engine/Internal.hs").read_text()
spec = Path("SPEC.md").read_text()
rust_block = re.search(
r"enum JobRefusal\s*\{(?P<body>.*?)\n\}",
rust,
re.S,
)
hs_block = re.search(
r"decodeJobRefusal\s*=\s*do.*?pure case reason of(?P<body>.*?)\n\s*unmodelled",
hs,
re.S,
)
assert rust_block and hs_block
rust_literals = re.findall(r'#\[error\("([^"]+)"\)\]', rust_block.group("body"))
hs_literals = re.findall(r'^\s*"([^"]+)"\s*->', hs_block.group("body"), re.M)
print("rust_literal_count =", len(rust_literals))
print("haskell_literal_count =", len(hs_literals))
print("literal_sets_match =", rust_literals == hs_literals)
print("rust_literals =", rust_literals)
print("spec_lists_canonical_literals =", all(literal in spec for literal in rust_literals))
print("spec_defines_reason_shape =", "[job_id, reason]" in spec)
PYRepository: dataclique/event-sorcery Length of output: 570 Document the canonical The Rust engine and Haskell binding use the same six literals. 🤖 Prompt for AI AgentsSource: Path instructions |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| withErrorBuffer :: (Ptr EsBuf -> IO value) -> IO value | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| withErrorBuffer action = | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| alloca $ \buffer -> do | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -495,3 +568,8 @@ readEngineError status buffer = do | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| emptyBuffer :: EsBuf | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| emptyBuffer = EsBuf nullPtr (0 :: CSize) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| -- | The byte a tag cell holds before an engine call writes its answer. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| unwrittenTag :: Word8 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| unwrittenTag = 255 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
Repository: dataclique/event-sorcery
Length of output: 162
🏁 Script executed:
Repository: dataclique/event-sorcery
Length of output: 50382
🏁 Script executed:
Repository: dataclique/event-sorcery
Length of output: 50382
🏁 Script executed:
Repository: dataclique/event-sorcery
Length of output: 37143
🏁 Script executed:
Repository: dataclique/event-sorcery
Length of output: 7156
🏁 Script executed:
Repository: dataclique/event-sorcery
Length of output: 290
Document the ABI minor floor as 3
The Rust engine exports ABI
0.3, andopenStorerejects engines below minor3. Add the raised floor and its compatibility impact toSPEC.md; it prevents bindings from opening ABI0.2engines, including stream-only deployments.🤖 Prompt for AI Agents