Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@

## Unreleased

- Corrected the canonical ownership document to describe the executable pure
flat-text reference separately from the unfinished stateful rope and installed
release. The historical basis-identity probe now supplies its own matching
frozen lawpack closure instead of copying the current application's closure.
Build-time and runtime checksum checks refuse historical input drift.

- Added DL-0159, a draft representation for the Edict-authored rope: schema 2
with typed Echo edges for every structural relation, canonical CBOR facts,
content-addressed immutable nodes, and an import anchor tying every head to
Expand Down
31 changes: 23 additions & 8 deletions docs/jim-component-ownership.md
Original file line number Diff line number Diff line change
Expand Up @@ -697,13 +697,28 @@ definitions or test oracles accidentally become fake runtime implementations.
| Installed release record | Echo | One complete closure was retained, installed, verified, and activated for a worldline under an explicit transition | That a particular command committed |
| Tick, conflict outcome, reading, receipt, and recovery evidence | Echo realm | What happened under one release, realm, epoch, basis, and admitted or rejected execution | What Jim should decide next |

The schema and oracle are already frozen under
`contracts/jedit/lawpacks/replace-range-v1/`. `ReplaceRange.edict` and its
complete application-owned lawpack closure do not yet exist in Jedit. Neither
does the release manifest that would bind `jim.core`, `jedit.text`, their entry
points, and the relevant profiles. Edict's generic application-owned lawpack
authoring and bounded-control prerequisites have landed, but only the real
application source can reveal the next honest compiler or target-profile gap.
The schema and independent oracle are frozen under
`contracts/jedit/lawpacks/replace-range-v1/`. Jedit now owns executable source
and its complete published lawpack closure under `edict/replace-range/`.
The public Edict build and independent verifier produce a pinned pure package
that Echo executes as a flat-text replacement reference, with range, UTF-8,
offset-boundary, no-op and resource refusals. The package and verifier report
are byte-identical across the verified macOS and Linux builds. The application
[README](../edict/replace-range/README.md) owns the exact build and runtime
reproduction instructions.

This reference computes bytes; it does not construct a persistent rope or
produce the domain's typed outcomes. Authored graph effects, atomic admission,
Tick/WAL/receipt/readings and fresh-engine recovery remain unimplemented for
this package. The standalone runtime host is test-only conformance scaffolding,
unreachable from the editor's production composition. The proposed persistent
rope source remains a noncompiling draft outside the application gate.

The release manifest binding `jim.core`, `jedit.text`, their entry points and
profiles, and the installed release that would activate it, also remain absent.
This working pure package refines the authored-source stage of the artifact
chain; it does not establish an installed Jim release or replace the current
native text-operation authority.

In summary, the artifact chain moves from application definition, to authored
source and lawpack closure, to compiler-produced package, to installed release,
Expand Down Expand Up @@ -1178,7 +1193,7 @@ but contradictory prose.
| Which TypeScript paths still own semantics? | Vim parsing, motion resolution, coordinate conversion, operation selection, and transition planning are executable today | Classify them explicitly as compatibility authority, not merely import or migration plumbing |
| Who owns text and rope contracts in target prose? | Some older documents say “Jedit” broadly, while the first draft grouped them under Jim | Name `jedit.text` as the application-owned text capability, `jim.core` as its semantic consumer, and Jedit as the product/body composition |
| Do documentation tests prove the canonical section? | Some policy tests search required phrases anywhere in a document | Scope tests to the named ownership sections and assert the complete contract, including test-only direct `ReplaceRange` invocation |
| Does the target exist in code? | `Jim.edict`, `ReplaceRange.edict`, `TextWindow.edict`, `JimRelease`, authority realms, durable conflict resolution, and materialization guarantee providers are absent or unproven | Keep every target statement labeled as target until compiler, runtime, recovery, and external-effect evidence exists |
| Does the target exist in code? | A compiler-produced pure flat-text `ReplaceRange.edict` reference exists; the authored persistent-rope operation, `Jim.edict`, `TextWindow.edict`, `JimRelease`, authority realms, durable conflict resolution, and materialization guarantee providers remain absent or unproven | Keep every target statement labeled as target until compiler, runtime, recovery, and external-effect evidence exists |

There is also a procedural gap. The clean architecture worktree is one commit
ahead of current Jedit `main`, and PR #300 carries these ownership corrections,
Expand Down
13 changes: 12 additions & 1 deletion edict/replace-range-probes/basis-identity/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
# SPDX-License-Identifier: Apache-2.0
# © James Ross Ω FLYING•ROBOTS <https://github.com/flyingrobots>
FROM node:22.23.1-bookworm AS historical-closure
WORKDIR /historical
COPY edict/replace-range-probes/basis-identity/application ./application
COPY edict/replace-range-probes/basis-identity/application-provenance.json ./application-provenance.json
COPY edict/replace-range-probes/basis-identity/verify-closure.mjs ./verify-closure.mjs
COPY edict/replace-range-probes/basis-identity/verify-closure.spec.mjs ./verify-closure.spec.mjs
RUN node --test verify-closure.spec.mjs \
&& node verify-closure.mjs /historical/application /historical/application-provenance.json /application-checksums.sha256

FROM rust:1.94.0-bookworm
WORKDIR /edict
RUN git init && git remote add origin https://github.com/flyingrobots/edict.git \
Expand All @@ -10,7 +19,9 @@ WORKDIR /echo
RUN git init && git remote add origin https://github.com/flyingrobots/echo.git \
&& git fetch --depth=1 origin 49e9efb68001dfd78563d18bac9359a87671e431 \
&& git archive FETCH_HEAD schemas/edict-provider/package/v1 | tar -x
COPY edict/replace-range /application-source
COPY --from=historical-closure /historical/application /application-source
COPY --from=historical-closure /historical/application-provenance.json /application-provenance.json
COPY --from=historical-closure /application-checksums.sha256 /application-checksums.sha256
COPY edict/replace-range-probes/basis-identity/ReplaceRange.edict /comparison-sources/ReplaceRange.edict
COPY edict/replace-range-probes/basis-identity/PayloadEquality.edict /comparison-sources/PayloadEquality.edict
COPY edict/replace-range-probes/basis-identity/build.sh /comparison-build.sh
Expand Down
20 changes: 18 additions & 2 deletions edict/replace-range-probes/basis-identity/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,17 @@ The COPY-based image builds the existing pinned compiler
`3f81f759e921a69b04fe8cf8e62e62f8f3dc7b7e` using Rust 1.94.0, fetches the
existing pinned provider `49e9efb68001dfd78563d18bac9359a87671e431`, and invokes
Edict's public JSONL application-build boundary. Each disposable application
copy retains the frozen application manifest and complete published lawpack;
only its source file changes. No host repository or Git directory is mounted.
copy uses `application/`, the frozen application manifest and complete published
lawpack from Jedit commit `9e6466150e43afc83966f9fe67c6ddce2f58d5bc`.
`application-provenance.json` records every retained file's SHA-256. The Node
preflight stage checks every hash, refuses missing or unrecorded files and
unsafe paths, then emits a checksum projection that also binds the provenance
JSON. The runtime build checks that projection before compiling either source. This closure's
manifest is `sha256:95758c1605894672cc9069fde01bb8b6e11842b053102660c9cd4f4d6f34d64e`,
matching both comparison sources. It is independent of the current flat-text
application, whose published closure may evolve. The build inserts only the
selected comparison source into the disposable copy. No host repository or Git
directory is mounted.
Comment thread
flyingrobots marked this conversation as resolved.
Resolved

The success marker is `JIM_BYTE_COMPARISON_PACKAGES_BUILT`. Output contains
`head/` and `payload/`, each with the emitted executable package and its separate
Expand All @@ -42,3 +51,10 @@ metered byte equality; it does not provide snapshot reads or make the full
ReplaceRange acceptance criteria complete. Generic fact reads, application-owned
codecs and rope semantics, admitted execution, independent oracle agreement,
Tick, receipts, WAL, and recovery remain required by #296.

The closure checker requires a build-owned immutable input tree, as supplied by
Docker `COPY`. It rechecks directories before descent and reads regular files
through descriptors opened with `O_NOFOLLOW`, including the provenance JSON.
This refuses a leaf symlink swapped after traversal. It does not provide a
sandbox for a hostile process concurrently replacing ancestor directories;
mutable trees shared with untrusted writers are outside this probe's contract.
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"schema": "jedit.probe-frozen-application/v1",
"sourceCommit": "9e6466150e43afc83966f9fe67c6ddce2f58d5bc",
"sourceRoot": "edict/replace-range",
"files": {
"edict.application.json": "sha256:3182577627cd1f88bf590f3a8481ef53476c83d783aa142182e7c65eb1f72f8b",
"vendor/jedit-text/adapter.cbor": "sha256:ab1437164084cbaf453f869c4302df9e648186fe6833bcb81c1e267c8dfeb6f9",
"vendor/jedit-text/adapter.sha256": "sha256:f8f24ec4077411189f7cdc73052c2149b24036a31535e95d4254fb6393e66421",
"vendor/jedit-text/echo-operation-configuration.cbor": "sha256:ea787368881f448021f2d71c72cbadbc487e59a09e9638acfc25ec3579a3609d",
"vendor/jedit-text/echo-operation-configuration.sha256": "sha256:583070043579837cfffb4949867bb672f71f935a45e20e6ecbf7caf7483d600c",
"vendor/jedit-text/edict.lawpack-output.json": "sha256:141c0000932ba19cff687e4173e40b0a38410f70bd511c9bc51f3fb3f73ee62b",
"vendor/jedit-text/exports.cbor": "sha256:cab9c575da49cb33289e45fc45afb9d7f05558dada734be7eb3acfbbabb1d4db",
"vendor/jedit-text/exports.sha256": "sha256:9bb11d9f8153c18af53b484526d9980b05c27eb20aa97e7623d1bf1ed5a69aea",
"vendor/jedit-text/manifest.cbor": "sha256:0323ed8e9510e473d329166d421dc7d8e1da353065c1cd2dee77e6313ba9bf91",
"vendor/jedit-text/manifest.sha256": "sha256:316cf602502a45cbab89b77b6344854edee750eaf1f0c8167da48d19ead75c22",
"vendor/jedit-text/verifier-rules.cbor": "sha256:e6d445fe8b4428307c274dd1a883b848d1aa72d1194730e75928cd1f375b2464",
"vendor/jedit-text/verifier-rules.sha256": "sha256:4fd69ab96251d649e9c9528bac6188839f0210b128ffc54701b9ee4ef6e7f7b7"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"schema": "edict.application/v1",
"coordinate": "jedit.text.replace_range@1",
"sources": [
"src/ReplaceRange.edict"
],
"lawpacks": [
{
"manifest": "vendor/jedit-text/manifest.cbor",
"exports": "vendor/jedit-text/exports.cbor",
"adapter": "vendor/jedit-text/adapter.cbor",
"targetConfiguration": "vendor/jedit-text/echo-operation-configuration.cbor"
}
],
"target": {
"profile": "echo.dpo@1",
"providerPackage": ".build/echo-provider"
},
"outputDirectory": ".build/application"
}
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
sha256:b8d9f15ef18dc99691ab1e034ca40a8b8ac52a1bc1b27597284f1edbaf84f049
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
¢japiVersionx(echo.operation-lowering-configuration/v1kprogramKindx!compiler-produced-bounded-pure/v1
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
sha256:bcb811b2d00d9824a256a26e48c14401c87fff509f2f75deb2ba703003a3f6d4
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
{
"schema": "edict.lawpack-output/v1",
"lawpackId": "jedit.text",
"lawpackVersion": "1",
"artifacts": [
{
"path": "manifest.cbor",
"kind": "manifest",
"coordinate": "edict.lawpack/v1",
"digest": "sha256:95758c1605894672cc9069fde01bb8b6e11842b053102660c9cd4f4d6f34d64e"
},
{
"path": "manifest.sha256",
"kind": "manifestDigest",
"coordinate": "edict.lawpack/v1",
"digest": "sha256:95758c1605894672cc9069fde01bb8b6e11842b053102660c9cd4f4d6f34d64e"
},
{
"path": "exports.cbor",
"kind": "exports",
"coordinate": "jedit.text.exports/v1",
"digest": "sha256:cbbc79fd92f09f341a1fae221a2a869bb64e15c511af39333e0453cd87fe456a"
},
{
"path": "exports.sha256",
"kind": "exportsDigest",
"coordinate": "jedit.text.exports/v1",
"digest": "sha256:cbbc79fd92f09f341a1fae221a2a869bb64e15c511af39333e0453cd87fe456a"
},
{
"path": "echo-operation-configuration.cbor",
"kind": "localResource",
"coordinate": "echo.operation-lowering-configuration/v1",
"digest": "sha256:bcb811b2d00d9824a256a26e48c14401c87fff509f2f75deb2ba703003a3f6d4"
},
{
"path": "echo-operation-configuration.sha256",
"kind": "localResourceDigest",
"coordinate": "echo.operation-lowering-configuration/v1",
"digest": "sha256:bcb811b2d00d9824a256a26e48c14401c87fff509f2f75deb2ba703003a3f6d4"
},
{
"path": "verifier-rules.cbor",
"kind": "localResource",
"coordinate": "jedit.text.verifier-rules/v1",
"digest": "sha256:364fb4ff98ae64fcd8d793aae3d7cb133ff8a1ce661330cea47688b13a0a823f"
},
{
"path": "verifier-rules.sha256",
"kind": "localResourceDigest",
"coordinate": "jedit.text.verifier-rules/v1",
"digest": "sha256:364fb4ff98ae64fcd8d793aae3d7cb133ff8a1ce661330cea47688b13a0a823f"
},
{
"path": "adapter.cbor",
"kind": "adapter",
"coordinate": "jedit.text.echo-adapter/v1",
"digest": "sha256:b8d9f15ef18dc99691ab1e034ca40a8b8ac52a1bc1b27597284f1edbaf84f049"
},
{
"path": "adapter.sha256",
"kind": "adapterDigest",
"coordinate": "jedit.text.echo-adapter/v1",
"digest": "sha256:b8d9f15ef18dc99691ab1e034ca40a8b8ac52a1bc1b27597284f1edbaf84f049"
}
]
}
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
sha256:cbbc79fd92f09f341a1fae221a2a869bb64e15c511af39333e0453cd87fe456a
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
sha256:95758c1605894672cc9069fde01bb8b6e11842b053102660c9cd4f4d6f34d64e
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
¤fschemasjedit.text.schema@1lschemaDigestxGsha256:f49b0ff6c9c7010d3a72b46734d47832853f496739a083edc41dddec3431bac7oruntimeOntologyugeneric-bounded-graphworacleIsExecutableInputô
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
sha256:364fb4ff98ae64fcd8d793aae3d7cb133ff8a1ce661330cea47688b13a0a823f
2 changes: 2 additions & 0 deletions edict/replace-range-probes/basis-identity/build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
# © James Ross Ω FLYING•ROBOTS <https://github.com/flyingrobots>
set -eu
[ -f /.dockerenv ] || { echo 'Run in the COPY-based Docker image' >&2; exit 1; }
(cd /application-source && sha256sum --check /application-checksums.sha256)
mkdir /comparison-output
for comparison in head payload; do
case "$comparison" in
Expand All @@ -12,6 +13,7 @@ for comparison in head payload; do
application="/comparison-$comparison"
mkdir "$application"
cp -R /application-source/. "$application/"
mkdir -p "$application/src"
cp "/comparison-sources/$source_file" "$application/src/ReplaceRange.edict"
mkdir -p "$application/.build"
cp -R /echo/schemas/edict-provider/package/v1 "$application/.build/echo-provider"
Expand Down
72 changes: 72 additions & 0 deletions edict/replace-range-probes/basis-identity/verify-closure.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
// SPDX-License-Identifier: Apache-2.0
// © James Ross Ω FLYING•ROBOTS <https://github.com/flyingrobots>
import { createHash } from 'node:crypto';
import { closeSync, constants, fstatSync, lstatSync, openSync, readFileSync, readdirSync, writeFileSync } from 'node:fs';
import { join, relative, resolve } from 'node:path';

const hash = bytes => createHash('sha256').update(bytes).digest('hex');

// The build owns an immutable COPY snapshot. Leaf descriptors also refuse links
// swapped after traversal; this is not a sandbox for hostile mutable ancestors.
function readRegular(path) {
if (typeof constants.O_NOFOLLOW !== 'number') throw new Error('O_NOFOLLOW is required');
const fd = openSync(path, constants.O_RDONLY | constants.O_NOFOLLOW);
try {
if (!fstatSync(fd).isFile()) throw new Error('nonregular historical input');
return readFileSync(fd);
} finally {
closeSync(fd);
}
}

try {
const [application, provenance, output] = process.argv.slice(2);
if (!application || !provenance || !output) throw new Error('expected application, provenance and checksum output');
const root = resolve(application);
const receiptBytes = readRegular(provenance);
const receipt = JSON.parse(receiptBytes);
if (receipt.schema !== 'jedit.probe-frozen-application/v1' ||
!/^[a-f0-9]{40}$/.test(receipt.sourceCommit) ||
receipt.files === null || typeof receipt.files !== 'object' || Array.isArray(receipt.files)) {
throw new Error('invalid provenance envelope');
}
const recorded = Object.entries(receipt.files);
if (recorded.length === 0) throw new Error('empty historical closure');
const actual = [];
function walk(directory, prefix = '') {
if (!lstatSync(directory).isDirectory()) throw new Error('nonregular historical directory');
for (const name of readdirSync(directory).sort()) {
const path = join(directory, name);
const entry = lstatSync(path);
const key = prefix + name;
if (entry.isDirectory()) walk(path, `${key}/`);
else if (entry.isFile()) actual.push(key);
else throw new Error(`nonregular historical input: ${key}`);
}
}
walk(root);
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Resolved
const checksums = [];
for (const [path, expected] of recorded) {
if (path.startsWith('/') || /[\\\r\n\t\0]/.test(path) ||
path.split('/').some(part => part === '' || part === '.' || part === '..') ||
typeof expected !== 'string' || !/^sha256:[a-f0-9]{64}$/.test(expected)) {
throw new Error('invalid recorded path or digest');
}
const bytes = readRegular(join(root, path));
if (`sha256:${hash(bytes)}` !== expected) throw new Error(`historical hash mismatch: ${path}`);
checksums.push(`${expected.slice(7)} ${path}`);
}
const listed = new Set(recorded.map(([path]) => path));
if (actual.length !== listed.size || actual.some(path => !listed.has(path))) {
throw new Error('unrecorded historical input');
}
// Bind the JSON envelope too, so runtime verification detects receipt drift.
const receiptPath = relative(root, resolve(provenance));
if (/[\\\r\n\t\0]/.test(receiptPath)) throw new Error('invalid provenance path');
checksums.push(`${hash(receiptBytes)} ${receiptPath}`);
writeFileSync(output, `${checksums.join('\n')}\n`);
process.stdout.write(`${JSON.stringify({ kind: 'FrozenClosureVerified', files: recorded.length })}\n`);
} catch (error) {
process.stderr.write(`${JSON.stringify({ kind: 'InvalidFrozenClosure', detail: error instanceof Error ? error.message : 'invalid closure' })}\n`);
process.exitCode = 1;
}
Loading
Loading