Repository navigation
feat(x5820): ActionIntent commits over CNP-0-JCS canonical bytes - #4
Conversation
Rebuilt on main@2fbcdbaf. Three files, no unrelated commits.
{"args_commitment":"c1","canonical_encoding":"hsp-jcs@v0",
"input_commitments":["a","b"],"numeric_profile":"cnp-0",
"requested_effects":["receipt","write"],"target_substrate":"myc",
"verb":"apply"}
→ ccc26b8b460fe2debf0ad069d55ec170a78b7b70861f1f54c03e401e4576c3be
RFC-0003 Part 01 §5.1, Tranche A3. Chosen because it is an authority gate:
actionBoundAuthority permits actuation only on an exact commitment match.
**One domain check, not two.** `domainError` is called by `validateIntent` AND
by the encoder. The previous version repeated only the surrogate check inside
the encoder while calling itself "refusing anything else" — it encoded
`requested_effects: [1]` as the JSON number 1 and returned a digest. Two guards
meant to agree, written twice, disagree.
**`requested_effects` is a set: deduplicated then ordered.** Sorting alone was
not set semantics; `["write","write"]` and `["write"]` request the same effect
and produced different commitments, letting a grant depend on how many times a
caller named an effect. Duplicates are canonicalised away rather than rejected —
a repeated effect is the same ask written twice, not a malformed ask.
**Unknown members are rejected, not dropped.** Silently discarding one lets two
callers commit to one digest believing they asked different things.
No dual-hash: d02d75ad… is not produced and a test asserts it. No commitment was
ever persisted.
Twelve direct-bypass controls, each requiring the encoder AND the digest path to
throw: wrong array member type in both arrays, invalid substrate, empty and
whitespace verb, malformed array field, extra member, missing member, non-object,
array, null, lone surrogate.
Bytes pinned, not only digests. BMP, non-BMP (a surrogate pair is one scalar and
is legal), lone-surrogate rejection in every string position. End-to-end on what
lands on disk: `propose --action-intent` writes the new commitment; an intent
with a lone surrogate exits 1 and writes nothing.
Standalone 261 passed / 0 failed; nested `deno task check` green.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DRHMVB9rUYNggn4wLmc1An
…fuse
Three P1s from the joint gate. All reproduced before fixing.
**Raw JSON erased forbidden evidence before validation.** Both CLI boundaries
did `JSON.parse(await Deno.readTextFile(...))`, which collapses duplicate member
names last-wins and replaces invalid UTF-8 with U+FFFD. So
`{"verb":"deny","verb":"apply",...}` wrote a proposal for an intent that also
said `deny`, and a `0xff` byte inside `verb` committed to a replacement
character nobody wrote.
RFC-0003 §5.1.1 rule 4 exists for exactly this, and the conformance kit's own
INTERFACE.md says three rejection categories "describe properties of the input
BYTES that a permissive JSON parser resolves before you can see them". I wrote
that sentence and then used a permissive parser at an authority boundary.
`parseActionIntentBytes` decodes UTF-8 fatally from bytes, scans the top-level
object for a repeated member name BEFORE `JSON.parse` can collapse it, and only
then normalizes. Names are decoded before comparison, so `"verb"` cannot
smuggle a second `verb` past the check.
dup proposals_written=0 duplicate-member-name: "verb" appears more than once
dup-esc proposals_written=0 duplicate-member-name: "verb" appears more than once
bad-utf8 proposals_written=0 invalid-utf8: the input is not well-formed UTF-8
**The shared check re-read mutable input.** `domainError(intent)` validated the
properties and `canonicalIntentText` read them again, so an enumerable getter
answered the validator with `["write"]` and the encoder with `[1]` — producing
canonical bytes containing a JSON number, and a digest over them.
`normalizeIntent` is now one operation that reads every property EXACTLY ONCE
into a local and returns owned copies; arrays are copied rather than aliased;
encoding uses only that snapshot. Controlled for four getter schedules: no
canonical text ever contains a non-string effect, and any digest that is produced
equals the digest of a validated value.
Scope held: no general JSON migration, no proxy sandbox. The strict path is used
by `--action-intent` only.
Standalone and nested checks green.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DRHMVB9rUYNggn4wLmc1An
PR Summary by QodoAdopt CNP-0-JCS commitments for ActionIntent authority grants
AI Description
Diagram
High-Level Assessment
Files changed (4)
|
Code Review by Qodo🐞 Bugs (0) 📘 Rule violations (0) 📎 Requirement gaps (0)
Great, no issues found!Qodo reviewed your code and found no material issues that require reviewTip of the day💡 Did you know, you can start a comment with 'qodo' or '@qodo' to chat about any finding |
|
Codex acceptance, final round 2/2. Reviewed exact head e02d7f9; replayed the duplicate-name, escaped-duplicate, invalid-UTF-8, changing-getter, and stored-descriptor E2E cases. Targeted tests and the standalone MYC check are green. Accepted for merge; this establishes the implementation side of the bounded ActionIntent adoption claim, not independent interoperability. |
Myc half of the joint ActionIntent adoption gate, round 2/2. Replaces PR #1, which pointed at
468ae52on an old base and was CONFLICTING.Myc candidate:
e02d7f98637c1ea7fcc793c7023e3e015bbecf7eTrinity candidate:
2db70569551a186b106765e03d00bed2bf2c05ef— trinity#27Base
main@2fbcdbaf. Three ActionIntent files plus the strict-intake wiring inx5800_propose.ts.Round-1 P1s closed
Raw JSON erased forbidden evidence. Both boundaries now take raw bytes: UTF-8 decoded fatally, duplicate top-level member names detected before
JSON.parsecollapses them, names decoded first so"verb"cannot smuggle a secondverb.Executed, at the CLI, asserting on disk:
Check-then-reread.
normalizeIntentreads every property exactly once into owned copies (arrays copied, not aliased); the encoder uses only that snapshot. Controlled for four getter schedules: no canonical text ever contains a non-string effect, and any digest produced equals a validated value's.Cross-stored E2E lives on the Trinity side (it needs both) — see trinity#27.
Boundaries
No general JSON migration; the strict path is used by
--action-intentonly. No proxy sandbox. No otherstable()touched. No status claim in this PR.