The DOM adapter's only test file asserts membership predicates ("if is a
render form") — zero tests inspect what render-to-dom actually builds
(hosts.md C23), and the file is excluded from the runner as browser-only.
Discovery: the browser-only assumption is false for render output —
(import (web adapter-dom)) disk-resolves in the OCaml runner and
render-to-dom works against its mock DOM. Add
web/tests/test-adapter-dom-render.sx (8 tests) pinning the adapter's real
output contract (probed first): text renders as a nodeType-3 child text
node; when/map wrap output in a FRAGMENT child; if inlines the chosen
branch; attrs/class/id land on the element; voids have no children.
Auto-included in default runs — first render-output coverage of the
1512-line adapter in the standard gate. Remaining depth (boolean attrs,
on-*/bind/ref/key, reactive attrs, hydration cursor) tracked on the
checklist. 254/0 standalone.
Test-only: no semantics edits, no push.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The synchronous harness binds mocks as plain NativeFns, so no harness test
could exercise the real CEK perform/suspend/resume path — the HO+perform
element-drop class (S10) was structurally invisible (hosts.md C21).
Add harness-run-perform to spec/harness.sx: drives make-cek-state/
cek-step-loop, services each (perform {:op X :args L}) suspension from the
session's platform mocks (entry logged before invocation, C22-consistent),
cek-resumes with the mock value, loops to terminal; clear error on an
unmocked op. Shared arity dispatch extracted as harness-invoke-mock.
Pins (gate-C21-perform-mode-harness): single suspension, arithmetic-frame
resume, sequential performs, unmocked-op error, and the S10 probe — map
over a perform-suspending lambda keeps ALL 3 elements through 3
suspensions on the CEK path (localizing the drop class to serving-JIT).
290/0 under OCaml run_tests; harness self-suite green.
Caveat (documented): requires the runner's cek-* driver bindings — absent
on bare sx_server/MCP, the same runner-only-binding theme as section B.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The interceptor appended the IO-log entry only after the mock returned, so
a throwing mock left no entry and error-path tests falsely reported "never
invoked" through assert-io-called/count (hosts.md C22, core.md K104).
spec/harness.sx make-interceptor now appends {:args :result nil :op}
BEFORE invoking the mock and updates :result in place via dict-set! on
return. This is W14-owned test infrastructure (PLAN.md W14 approach item
4), not a semantics edit.
Pins: suite gate-C22-throwing-mock-logged (throwing mock leaves an entry
with pending result; happy path updates the result; mixed throwing +
successful sequence counts all calls). Harness self-suite (15 tests) and
test-relate-picker (the only other harness consumer) verified green;
285/0 on the pins run.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
mcp_tree.ml's parallel primitive table drifted from sx_primitives.ml —
the spec-mandated harness verification path silently produced false
findings ((get {:a 1} :a 99) -> nil vs 1, char-class vs substring split,
etc.). dc7aa709 aligned 8 entries as a stopgap; the real fix (linking
sx_primitives) is hosts-lane.
Add scripts/test-harness-parity.sh: drives mcp_tree.exe sx_eval via raw
JSON-RPC and a fresh sx_server.exe via the epoch protocol, runs the
finding's 12-probe battery through both, fails on any divergence (errors
compared by inner message). 12/12 parity today — the stopgap holds and
can no longer rot silently.
Test-only: no semantics edits, no push.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Section-B audit, all verified live over the epoch protocol. Runner-only
bindings absent from production: values, call-with-values (run_tests.ml
:1131/:1140), contains-char? (rt.ml:728 + rt.js:85), trim-right (JS runner
ONLY — absent even from the OCaml runner), sha3-256 (rt.ml:745 + rt.js:88;
production's real primitive is crypto-sha3-256).
Consequences pinned: (canonical-serialize 42) on a fresh server errors
"Undefined symbol: contains-char?" — content addressing broken for ANY
number outside the runners. And BOTH runners' sha3-256 are FAKE stubs
(OCaml: Hashtbl.hash), so every test-computed CID differs from production.
scripts/test-env-parity.sh is a bidirectional ledger: MUST_HAVE bindings
going missing fail; a KNOWN_DRIFT binding APPEARING also fails with
instructions to move it to MUST_HAVE and flip the consequence pin — the
ledger cannot rot silently in either direction. 7/7 green.
Test-only: no semantics edits, no push.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Pre-fix, a routing-failure page was stored in the HTTP response cache as
200 and served byte-identically to every later visitor until restart
(cold 2s -> warm 0.0005s). dc7aa709 made http_render_page return
(html, is_error) and gated cache insertion on `not is_err`.
Extend scripts/test-protocol-gate.sh with an HTTP-mode case: fresh
sx_server.exe --http on a random port (timeout-bounded, own child killed),
GET the same nonexistent path twice, assert both requests re-render (two
[sx-http] render lines) and the "[cache] ... error page, not cached" gate
line appears. Standalone-worktree caveat (all docs pages render as soft
error pages, so no positive cache control) documented in the script.
5/5 protocol-gate green; 267/0 sx gate pins. All seven section-A test-debt
pins now landed (K18, K20, K09/K11/K39, K49, crit-2, C1/C1b, S4).
Test-only: no semantics edits, no push.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Pre-fix, one malformed or non-ASCII line on sx_server's top-level command
channel raised an uncaught Parse_error and killed the whole shared process
(bridges + conformance runners). dc7aa709 guards the parse; the server now
answers (error N "Malformed command line: ...") and keeps serving.
Add scripts/test-protocol-gate.sh: per case, spawn a fresh timeout-bounded
sx_server.exe (never touches a shared process) and assert the error
response, the follow-up epoch still evaluating, and a clean exit. Cases:
C1 unterminated list + garbage line, C1b non-ASCII byte (exact review
repros from plans/sx-review/hosts.md), plus a well-formed control. 4/4
green. Structured to grow into W14 section E's protocol fuzz suite (C3-C7).
Test-only: no semantics edits, no push.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
crit-2's failure mode discards every frame outside the signal site —
including the covering test's own assert — which is why the shipped test
"signal returns handler value to call site" passed vacuously pre-fix. A
plain assert pin would inherit that vacuity on regression.
Add suite gate-crit2-signal-return-kont with a side-effect sentinel: test 1
runs the core.md repros ((list "outer" (handler-bind ... (+ 1
(signal-condition 5))) "end") -> ("outer" 43 "end"); raise-continuable ->
143) then set!s a top-level flag; test 2 independently asserts the flag, so
a dropped continuation fails loudly even though test 1 would "pass". Third
test pins the shipped-test expression (51). 267 passed / 0 failed under
OCaml run_tests.
Test-only: no semantics edits, no push.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
K49: area/base/embed/param/track were in VOID_ELEMENTS but missing from
HTML_TAGS — render fell through to "Undefined symbol: base". dc7aa709 fixed
spec/render.sx; add suite gate-K49-void-elements-renderable (3 tests): the
spec registry contains all five, and render-to-html renders each as a
self-closing void. 264 passed / 0 failed under OCaml run_tests.
DISCOVERY (recorded in the briefing's Blocked section): the generated
hosts/ocaml/lib/sx_render.ml was never regenerated after the spec fix — its
stale html_tags_list still lacks the five tags, so the runner's native
render-html path STILL errors. Fix is a bootstrap_render.py regen (hosts
lane, out of scope for this test-only loop). Live evidence for F13
(regen-diff CI gate). Pin covers the spec side only for now.
Also corrects the checklist label: K49 = void elements; the depth/cycle
guard is K16 (OPEN, W8).
Test-only: no semantics edits, no push.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Three dc7aa709 fixes shipped without pinning tests:
- K09: R7RS longhand (unquote-splicing X) now splices (was silent zero-splice)
- K11: guard re-raise sentinel gensym'd — a user value shaped like
(list '__guard-reraise__ X) is data, not a forged re-raise
- K39: (do ((fn (x) x) 5) 99) -> 99, not a misparsed Scheme do-loop
Add suites gate-K09-longhand-unquote-splicing, gate-K11-guard-reraise-forgeable,
gate-K39-do-iife-head to spec/tests/test-gate-pins.sx with exact reprs from
plans/sx-review/core.md. 261 passed / 0 failed under OCaml run_tests.
Test-only: no semantics edits, no push.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
contains? did not support dict key membership in the real runtime —
(contains? {:a 1} :a) threw "contains?: 2 args", contradicting its own :doc.
The fix landed (primitives.sx + sx_primitives.ml) but had no pinning test.
Add suite gate-K20-contains-dict to spec/tests/test-gate-pins.sx (4 tests,
repro from plans/sx-review/core.md): present key true, missing key false,
list membership + string substring unchanged. 8/8 green under OCaml run_tests.
Test-only: no semantics edits, no push.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The dc7aa709 quick-wins batch fixed `expt`'s silent 63-bit int wrap (now
promotes to float like +/*) but shipped no pinning test — a regression would
pass silently. Add spec/tests/test-gate-pins.sx suite gate-K18-expt-overflow
(4 tests, minimal reprs from plans/sx-review/core.md): small exponents exact,
2^62 and 2^100 do not wrap, 2^100 is a float. 4/4 green under OCaml run_tests.
Also bootstraps plans/agent-briefings/sx-gate-loop.md (the loop's own briefing,
absent until now) with the W14 checklist derived from PLAN.md §W14.
Test-only: no semantics edits, no push.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Adds a starting-point decision-commit on the coordinator branch
(sx1:9f05cceb...) marking the state where all review infrastructure is in
place — plan, rulings, quick-wins batch (dc7aa709), and the forge itself —
as the baseline from which the fix program starts. Records the sequencing
rule (W14 test-gate first, then W1/K01) so the next agent picks up correctly.
Coordinator branch: spawn -> baseline -> done -> START (4 commits).
forge.sxdata re-dumped (46KB); forge-build.sxsrc stays the reproducible source.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Built the SX-review remediation program as native fed-sx objects using the
now-green forge stack (sx-git 267/267, sx-gitea 615/615, agentic-sx 196/196):
- gitea-sx forge repo "rose-ash/sx-review" (one persist backend)
- agentic-sx session: coordinator + 16 workstream agent branches
(agents/ws-W1 .. ws-W16), each with a briefing (goal + finding-ids + status)
and a finding-commit carrying its workstream as queryable SX data
- baseline decision-commit sx1:a495549... (MANIFEST: 217 findings / 16
workstreams / real-git a24c8796 / done-commit dc7aa709)
- the completed quick-wins batch recorded as a refactor-commit
forge-build.sxsrc is the reproducible source (content-addressed → re-running
yields identical CIDs); forge.sxdata is the durable kv+stream snapshot
(45KB, 299 native sx1: objects). Load order = agentic conformance base +
relations + gitea/repo; run bounded, never the shared MCP image.
The review is now first-class queryable data in the native store, not just
markdown — each workstream/finding is addressable by CID.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The conformance lane added F16-F19 after the master ledger was built; they
were present in the copied evidence file but absent from PLAN.md. Added:
- W16 (Hyperscript shipped-kernel conformance): F16 shipped host-call-fn
binding gap (~900 tests, one-liner), F17 dropped jit-exclude! (sync drift),
F18 mock-DOM red-band re-baseline + 9 WASM-only bisect, F19 corpus drift +
inverted assert= labels
- ledger rows F16-F19; conf-S2 marked RESOLVED (superseded by F16/17/18)
Caveat recorded: hs engine may be absent from the production boot list, so
F16/F17 may be latent not live — confirm before treating as an outage.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Brings plans/agentic-sx-status.md (Phases 1-4 status, 196/196, and the
proposed rulings for held Phases 5/7/8/9). lib/agentic itself was already
merged at de9ace70 and is unchanged.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Failing test first (red: a probe with a raising actual-expr VANISHED — delta 0, total unchanged —
because the loader skips a raising top-level form and args are eager). Fix: host-bl-test is now a
MACRO expanding to (host-bl--check name (fn () actual) expected); the check evaluates the thunk under
(guard (e (true {:__raised …})) …), so an SX raise is recorded as a failure with the error instead
of disappearing. Native exceptions still escape guard — those already fail loud via conformance's
error grep, so this closes the actual silent-skip gap. Keeps the next TDD loop honest.
R2 DEFERRED: investigating it surfaced that lib/host serializes ALL handler evaluation per peer under
one mutex (held across persist IO + the outbound http-request) — zero intra-peer concurrency, so the
outbox 'race' is masked. Logged in plans + memory as the real concurrency task: narrow the handler
mutex for throughput (the multi-co-op future forces it, and that's when masked races become real).
blog suite 260/260; full conformance 662/662.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Durable copy of /tmp/sx-build/agentic-status.md: what was built (196/196),
boundary conventions, the 11 open design questions for held Phases 5/7/8/9,
and the proposed rulings awaiting sign-off.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Import from an IMMUTABLE snapshot (git archive), not the live tree — a
replay diverges the moment a source file changes (the forge's own
non-fast-forward check caught exactly that). import-stage-msg! carries
the source SHA in the commit message; import-delete-remote! + push
replaces a partial import's history in two requests.
rose-ash mirrored to sx.sx-web.org/giles/rose-ash: 4468 files @
4a7c05a2, one commit, zero skipped, single push under the linear wire.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The closure walk rebuilt its seen-set with assoc — which on this kernel
copies the entire hashtable per call — and stacked pending cids with
concat; pack-cids then insertion-sorted the result. All three are
quadratic, which surfaced the moment a real repo (4.5k files) went over
the wire: a single push spent an hour in the walk. The seen-set is now a
private dict mutated in place (dict-set!, the acl engine's own pattern),
pending cids are cons-stacked, and packs are unsorted (order is
irrelevant to the receiver). Wire suite stays 78/78; every clone/fetch/
push on repo-scale histories now walks each object once.
lib/gitea/import.sx: working-tree importer — file-read + http-request
adapt the Phase 3 wire client to a live server (gitea/http-app);
staging (deterministic commits, so an interrupted import replays to
identical CIDs and resumes without re-pushing) is separate from the
single delta push; pack lines that exceed the pkt limit are skipped and
reported.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
lib/gitea/serve.sx: durable live forge on the kernel persist store
(SX_PERSIST_DIR) with idempotent seeding (instance id, admin user +
rotating token, welcome repo), blocking in the native http-listen loop
via host/native-handler — the same wiring that serves blog.rose-ash.com.
lib/gitea/serve.sh: full-stack launcher (every substrate the eight
phases compose, in dependency order, + dream/session for the cookie
bridge) — container entrypoint and local launcher in one.
docker-compose.dev-sx-gitea.yml: sx_docs image, bind-mounted worktree +
binary, /root/sx-gitea-persist for durable state, externalnet so Caddy
can proxy sx.sx-web.org. Serving JIT off until validated for this path.
Smoke-tested locally: pages, authed API, markdown-rendered issues,
pkt-line ref advertisement, 401 gating, and full state survival across
a restart against the same persist dir.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
lib/gitea/fed.sx: forges federate as peers. Each forge carries an
instance id; users and repos project as AP actor documents (Person/
Group/Repository with inbox/outbox + clone endpoint); the outbox is the
activity log in an AP-shaped envelope.
Trust follows the events-federation pattern — a kv set of peer ids
RE-CHECKED on every operation (inbox, mirror sync, delivery), so
revoking a peer takes effect immediately; peer transports (dream app
fns) live only in the runtime cache.
Inbox (POST /api/ap/inbox, trust-gated): every accepted activity lands
in a federated log with :origin provenance; open-issue/comment/open-pr
MATERIALIZE — the foreign author becomes an auto-created proxy user
'<name>@<peer>' and the issue/comment/PR is created locally under that
identity. fed-deliver! pushes public-repo activities (cursor-based,
never private) to every trusted peer's inbox. Cross-instance repo
follow = mirror!/mirror-sync! over the Phase 3 wire client.
fed-timeline merges local + foreign activities with provenance tags.
Suite: two in-memory forges federating end to end — actor docs, trust
lifecycle, materialization, proxy-user reuse, wire inbox 400/403/200,
mirrors (clone/sync/trust-revocation), cursor delivery, timelines.
Adds lib/gitea/README.md (composition map, architectural rules, known
limits). Final scoreboard: 615/615 across repo/access/wire/issues/pr/
activity/search/fed.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
lib/gitea/search.sx: the forge builds document corpora SX-side — code
files from the default branch head (path + blob text), issues (title +
body + comments), PRs (title + body + reviews) — embeds them as one
haskell-on-sx program and asks searchRankTfIdf for ranked doc ids
(terms, AND/OR/NOT, phrases).
Cost model honored: one evaluation parses the Haskell layers
(~20s CPU), extra queries are nearly free — so the core primitive is
gitea/search-multi (any number of corpora and queries in a single
evaluation; each corpus an idxN binding) and only the six layers
searchRankTfIdf needs are compiled, not the full search/src. The test
suite runs its thirteen SX-level queries over five corpora as ONE
evaluation.
Global search spans exactly the repos the caller can read. Web:
/:owner/:name/search page (kind filter), repo + global JSON search.
Suite timeout raised to 900s for the haskell-backed suites.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
lib/gitea/activity.sx: every forge action lands as a feed activity in an
append-only persist log stream. Instrumentation is done IN the runtime —
repo-create!/issue-create!/issue-comment!/pr-create!/pr-review!/pr-merge!
are redefined around their originals, so SX callers and web handlers emit
activity with zero call-site edits (failed mutations emit nothing).
Timelines are lib/feed (APL) queries: global/repo/user, newest-first,
visibility follows repo access (private-repo activity invisible to
non-readers). Follows (user: or repo: targets) drive a dashboard of
followed actors/repos minus one's own actions.
Notifications ride lib/events durable delivery: activities after a
cursor expand to (id recipient body) messages (comment -> author+
participants, review/merge -> PR author, open-issue -> assignees, never
the actor), ev/deliver-messages runs the at-least-once digest flow, and
delivered messages file into per-user kv inboxes; the cursor advance
makes reruns no-ops.
Web: /activity + /:owner/:name/activity pages, user-activity/dashboard/
follow/notifications/notify-run JSON API. gitea/all-routes now hoists
every /api/* route ahead of the wildcard /:owner/:name patterns so later
packs can add API endpoints without being shadowed.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
lib/gitea/pr.sx: PRs as kv records sharing the per-repo number counter
with issues. Diffs are LIVE, computed from the merge base of the current
branch heads to the source head via sx-git (no spurious deletions when
the target moves on). Reviews: latest verdict per reviewer wins; authors
cannot review their own PR; approved? = some approve and no outstanding
request-changes.
Lifecycle is a lib/flow durable workflow (deterministic-replay suspend):
open -(approval)-> approved -(merge)-> merged; review! resumes the
approval suspend when the verdict set first approves, merge! resumes the
rest, close! cancels, reopen! starts a fresh flow. The flow env lives in
the forge handle; the record's :state stays the source of truth.
Merge via git/merge-commits over the merge base: up-to-date, fast-
forward (ref move only), true two-parent merge commit, or conflicts with
the conflicting paths. Every ref move is branch-cas! — concurrent pushes
surface as 'stale'. Merge queue: approved PRs merge in order,
failures stay queued.
Web: pulls list + PR page (body html, reviews, lifecycle, unified diff),
JSON API for create/review/merge (409 on conflicts/stale)/close (author
or write)/enqueue/queue-process.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
lib/gitea/issues.sx: issues as kv records (zero-padded per-repo
numbering, title/author/state, sorted label+assignee sets, Markdown
body, comment thread). Bodies and comments are content-on-sx documents:
content/from-markdown -> block doc -> content/html for pages, with the
round-trip law asserted in the suite. The issue graph (issue->repo
parent, author origin, assignee member, label link, commenter reply) is
DERIVED into lib/relations facts and rebuilt on fact change — same
pattern as the acl db, so deleting a repo can never dangle edges.
Views: open/closed/by-label/by-assignee; graph queries: repo-issue-nodes,
user-authored, user-assigned, label-issues, issue-participants.
Web: issues list + issue page (rendered HTML body + comments), JSON API:
create (any authenticated reader), comment, close/reopen (author or
write), label/assignee management (write). All read-gated like the rest.
Infra: gitea/route-packs registry — wire/issues append their routes at
load; gitea/app serves all packs. repo-delete! now purges collab/issue/
issue-seq rows too (ghost-state regression tested). Conformance runner
gains per-suite extra modules; the issues suite loads relations +
smalltalk + content (~5s).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Server (sx_server.ml):
- HTTP mode: JIT hook now opt-in via SX_SERVING_JIT, matching epoch mode
(was unconditional — live serving-JIT miscompiles J1/J2/J3 de-risked)
- command channel: malformed/non-ASCII line returns an error response
instead of killing the shared process (C1/C1b)
- response cache: soft error pages no longer cached (S4);
http_render_page returns (html, is_error)
Kernel spec + regen:
- crit-2: signal-return frame stored the saved kont under :f but the reader
looked up "saved-kont" — handler value became the whole program's result
and the covering test passed vacuously. Fixed; raise-continuable now also
resumes at the raise site (rest-k, not unwound-k), mirroring signal-condition
- quasiquote: R7RS longhand unquote-splicing aliased to splice-unquote
(used to serialize literally — silent zero-splice)
- guard: re-raise sentinel gensym'd per execution (was forgeable by any
(list '__guard-reraise__ x) value)
- do: IIFE-head form no longer misparses as a Scheme do-loop
- render: area/base/embed/param/track added to HTML_TAGS (were void-only
and rendered as Undefined symbol)
- REGEN REPAIR: checked-in sx_ref.ml carried hand-written additions that
every regeneration silently lost (let-values/define-values/delay/
delay-force registrations, AdtValue define-type) plus 5 regen blockers
(arrow-name mangling, 3-arg get, &rest defines, HO-position helper refs,
transpiler prim-table gaps). Moved into bootstrap.py FIXUPS/skips and the
transpiler prim table — regen is now reproducible, compiles, and tests
at baseline (CI Dockerfile.test steps 3-4 could not previously have
produced a compiling kernel)
Primitives:
- contains?: dict key-check arm per its spec doc
- expt: promotes to float on int63 overflow ((expt 2 100) returned 0)
- mcp_tree parity with sx_primitives: get (Integer indices + 3-arg default),
split (literal substring, was char-class — the historical gotcha lived
here), empty? on ""/{}, contains?, equal?, keyword-name, char-code
(Integer), parse-number (Integer-aware)
Python/docs:
- shared/sx/boundary.py: dead validation now logs a one-time WARNING instead
of silently no-oping (full revival gated: tier-1 declarations deleted and
SX_BOUNDARY_STRICT=1 is live in production compose)
- CLAUDE.md: canonical reference now points at spec/*.sx; island authoring
rules corrected (let IS sequential, bodies ARE implicit begin)
Verification: full suite 5762 passed / 274 failed — fail set byte-identical
to the pre-change baseline (273 in-progress hs-* + pre-existing r7rs radix
shadow). All repros verified fixed on both the native binary and the rebuilt
WASM browser kernel. Review findings: /tmp/sx-review/*.md
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
lib/gitea/wire.sx: git-style pkt-line framing (byte-compatible hex4
lengths + flush sections); object closure walker (commits/trees/blobs/
tags) with missing-object detection; wants/haves pack negotiation.
Objects travel as '<cid> <serialized-sx>' pkt lines — receivers re-derive
the CID from the bytes, so packs are tamper-evident by construction.
Server endpoints: GET info/refs (read-gated advertisement incl. '@ HEAD'
symref line), POST git-upload-pack (read), POST git-receive-pack (write;
401/403/404 like the rest of the API) with per-ref command application:
create/update/delete via ref-CAS, fast-forward enforcement on heads/*,
closure-completeness check, stale detection, heads|tags-only.
Client: gitea/remote over any dream app fn — ls-remote, clone! (sets
HEAD + default-branch, cleans up on unreachable remote), mirror fetch!,
push!/push-delete! with local pack computation. Suite syncs two
in-memory forges end to end: clone, incremental fetch, push, non-ff
rejection + recovery, branch create/delete, tag push, private-repo
credentialed round trip.
sx-parse comes from spec/parser.sx on the OCaml server host — added to
the conformance load order. Also merged loops/git (git-wire export/
import adapters, 267/267) for future stock-git interop.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
lib/gitea/access.sx: repo role groups (admin>write>read) as acl facts
saturated by the datalog engine; user-owner => admin; collaborators
(per-repo role, upsert); org teams (one role, 'all' or scoped repo
list); org-admin?; visible-repos; create-allowed?; bearer tokens in kv.
Facts derived from forge state, acl db cached in the forge handle and
rebuilt only when facts change.
lib/gitea/web.sx: every repo route now requires read (404 hides private
repos); repo create needs owner/org-admin, delete + collaborator API
need admin (401 no credentials / 403 not allowed); index + /api/repos
list only visible repos; PUT/DELETE collab endpoints.
tests/access.sx (103) + repo suite updated for gating (91). Fixed a
web.sx corruption from the known sx_find_all/sx_replace_node path
mismatch by rewriting via sx_write_file; suite timeout 300->600s.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Deterministic replay IS the durability mechanism: every transition re-runs a
self-contained flow program (defflow source + flow/start + replay of all
recorded resume values), so the only durable state is {:flow :input :resumes}
in persist kv — restart-safe by construction (fresh space handles over the
same backend resume mid-flight runs). fork-an-agent-run = copy the record;
the two replays diverge independently. Effects are data (suspend tags +
typed request envelopes surface as plain SX); transitions ride the Phase-3
trace buffer so session history travels with the next commit. Guest numeric
results compared with = per house convention. 43/43 (196/196 total).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Per-agent buffer = persist append-only log stream + kv drain cursor;
commit-with-trace! drains everything-since-last-commit into a console-trace
object and binds it git-note style (ref notes/trace/<commit-cid> -> trace
cid). Trace never enters the commit tree; binding is a re-bindable ref layer
over immutable objects; failed commits keep the buffer; plain commit! leaves
binding to the agent. 35/35 (153/153 total).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
space handle (repo + relations Datalog db); spawn! = branch-from-briefing
with a genesis spawn commit at the fork point; commit! verb snapshots a full
worktree VALUE into a typed agent-commit and CAS-advances the branch (no
shared index — multi-agent safe). Topology: fork-point via merge-base,
agents from refs, typed edges sub-agent-of/reviews/merges. Session merges
always record a two-parent session-merge commit (no-ff); conflicts commit
nothing and conclude via merge-resolve!. 53/53 (118/118 total).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
lib/git/import.sx parses loose payloads back to native objects bottom-up
over an export-set table: tree mode/name/raw-sha triples, ident lines,
header/message split, committer stored only when distinct so export
defaults regenerate identical bytes. Laws verified: export->import->export
is BYTE-IDENTICAL (head sha + every object), imported blobs/default-mode
trees regain their original native cids, 100755/tags/distinct-committer/
multi-line messages all survive. 15/15, total 267/267.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Type registry (briefing / console-trace / behaviour TAG / agent-commit +
spawn/finding/refactor/test/session-merge/decision subtypes) with reflexive
transitive is-a? and create-only register-type!. Agent commits ARE git
commits (:agent-type rides as an open field, participates in the CID, DAG
machinery applies unchanged). 65/65.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Textual diff3 built on the Myers scripts: non-eq regions clustered by strict
base-interval overlap (same-point insert pairs cluster too); one-sided
clusters apply, two-sided take shared result or emit <<<<<<</|||||||/=======/
>>>>>>> markers with base section. Per-path 3-way tree merge with blob-level
auto-merge and delete/modify flagging; merge-commits handles up-to-date /
fast-forward / merged / conflicts, unrelated histories merge over an empty
base. (Content CvRDT not reused deliberately: its state-based LWW block
semantics differ from base-anchored 3-way; the path-set merge here is the
same idea applied natively.) 28/28, total 187/187.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Myers O(ND) forward/backtrack over line vectors (dict-vec), edit script
{:op eq|del|add :line}, reconstruction invariants both sides, paper example
D=5 verified; unified hunks with context 3, merged ranges, exact header
math for empty sides; tree/commit structural diff over flattened trees;
whole-commit unified render. 27/27, total 159/159.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Worktree is a value (path->data dict). tree-from-files/tree-files round-trip
through real tree objects (cid-identical to hand-built trees); index =
{:base tree-cid :staged overlay} in kv with add!/rm!/unstage!/index-tree!;
status = three-way dict diff (HEAD vs index vs worktree) with
staged/unstaged/untracked. 26/26, total 132/132.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Ref value = {:cid} | {:symref}; atomic moves via persist/kv-cas old-value
expect, create-only branches via kv-put-new; bounded symref resolution;
per-ref append-only reflog on the persist log facet. 38/38, total 76/76.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Objects are plain dicts over persist kv, addressed by sx1:<sha256> of the
artdag/canon canonical form (sorted dict keys) — native CIDs, extensible
fields participate in identity. 38/38.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>