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
18 changes: 11 additions & 7 deletions METHOD.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,17 @@ The Echo work doctrine: A backlog, a loop, and honest bookkeeping.

## Backlog Lanes

| Lane | Purpose |
| :---------------- | :--------------------------------------- |
| **`asap/`** | Imminent work; pull into the next cycle. |
| **`up-next/`** | Queued after `asap/`. |
| **`cool-ideas/`** | Uncommitted experiments. |
| **`bad-code/`** | Technical debt that must be addressed. |
| **`inbox/`** | Raw ideas. |
| Lane | Purpose |
| :---------------- | :---------------------------------------------------------- |
| **`asap/`** | Imminent work; pull into the next cycle. |
| **`v0.1.0/`** | Release-bar blockers for the local contract-host milestone. |
| **`up-next/`** | Queued after `asap/`, outside the release-bar lane. |
| **`cool-ideas/`** | Uncommitted experiments. |
| **`bad-code/`** | Technical debt that must be addressed. |
| **`inbox/`** | Raw ideas. |

`v0.1.0/` is a milestone lane, not an automatic priority override. Move a
release-blocking card into `asap/` only when it becomes the current pull.

## The Cycle Loop

Expand Down
24 changes: 20 additions & 4 deletions crates/method/src/graph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,14 @@ use serde::Serialize;

use crate::workspace::MethodWorkspace;

const GRAPH_LANES: &[&str] = &["asap", "up-next", "inbox", "cool-ideas", "bad-code"];
const GRAPH_LANES: &[&str] = &[
"asap",
"up-next",
"v0.1.0",
"inbox",
"cool-ideas",
"bad-code",
];

const TASK_SECTION_PREFIX: &str = "## T-";

Expand Down Expand Up @@ -442,9 +449,10 @@ impl TaskGraph {
.map(|id| format!(" `{id}`"))
.unwrap_or_default();
let task_link = task_markdown_link(task);
let source_link = method_docs_relative_link_target(&task.source_path);
lines.push(format!(
"- `{}` `{}`{}: {} (source: [`{}`]({}))",
task.id, task.lane, native, task_link, task.source_path, task.source_path
task.id, task.lane, native, task_link, task.source_path, source_link
));
}
lines.push(String::new());
Expand Down Expand Up @@ -1180,16 +1188,24 @@ fn remove_task_tokens(raw: &str) -> String {

fn task_markdown_link(task: &TaskNode) -> String {
let title = task.title.replace('|', "\\|");
let target = method_docs_relative_link_target(&task.source_path);
if let Some(anchor) = &task.anchor {
format!("[{}]({}#{})", title, task.source_path, anchor)
format!("[{title}]({target}#{anchor})")
} else {
format!("[{}]({})", title, task.source_path)
format!("[{title}]({target})")
}
}

fn method_docs_relative_link_target(source_path: &str) -> &str {
source_path
.strip_prefix("docs/method/")
.unwrap_or(source_path)
}

fn lane_colors(lane: &str) -> (&'static str, &'static str) {
match lane {
"asap" => ("#fff3bf", "#b08900"),
"v0.1.0" => ("#dcfce7", "#15803d"),
"up-next" => ("#dbeafe", "#1d4ed8"),
"inbox" => ("#e5e7eb", "#4b5563"),
"cool-ideas" => ("#ede9fe", "#7c3aed"),
Expand Down
9 changes: 8 additions & 1 deletion crates/method/src/workspace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,14 @@
use std::path::{Path, PathBuf};

/// Known backlog lane names.
pub(crate) const LANES: &[&str] = &["inbox", "asap", "up-next", "cool-ideas", "bad-code"];
pub(crate) const LANES: &[&str] = &[
"inbox",
"asap",
"v0.1.0",
"up-next",
"cool-ideas",
"bad-code",
];

/// A validated METHOD workspace rooted at a filesystem path.
pub struct MethodWorkspace {
Expand Down
58 changes: 57 additions & 1 deletion crates/method/tests/graph_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,14 @@ use method::graph::TaskGraph;
use method::workspace::MethodWorkspace;

fn scaffold(root: &std::path::Path) {
for lane in &["inbox", "asap", "up-next", "cool-ideas", "bad-code"] {
for lane in &[
"inbox",
"asap",
"v0.1.0",
"up-next",
"cool-ideas",
"bad-code",
] {
fs::create_dir_all(root.join(format!("docs/method/backlog/{lane}"))).expect("create lane");
}
fs::create_dir_all(root.join("docs/design")).expect("create design");
Expand Down Expand Up @@ -111,6 +118,55 @@ fn matrix_csv_has_square_shape() {
assert!(csv.contains("depends on"));
}

#[test]
fn matrix_markdown_links_are_relative_to_method_docs_root() {
let tmp = tempfile::tempdir().expect("tempdir");
scaffold(tmp.path());

fs::write(
tmp.path()
.join("docs/method/backlog/v0.1.0/KERNEL_release_bar.md"),
"# Release Bar\n",
)
.expect("write release bar");

let workspace = MethodWorkspace::discover(tmp.path()).expect("discover");
let graph = TaskGraph::build(&workspace).expect("graph");
let matrix = graph.render_matrix_markdown();

assert!(matrix.contains("[Release Bar](backlog/v0.1.0/KERNEL_release_bar.md)"));
assert!(matrix.contains(
"(source: [`docs/method/backlog/v0.1.0/KERNEL_release_bar.md`](backlog/v0.1.0/KERNEL_release_bar.md))"
));
}

#[test]
fn milestone_lane_does_not_preempt_up_next_frontier_order() {
let tmp = tempfile::tempdir().expect("tempdir");
scaffold(tmp.path());

fs::write(
tmp.path().join("docs/method/backlog/up-next/A_queued.md"),
"# Queued\n",
)
.expect("write queued");
fs::write(
tmp.path()
.join("docs/method/backlog/v0.1.0/KERNEL_release_bar.md"),
"# Release Bar\n",
)
.expect("write release bar");

let workspace = MethodWorkspace::discover(tmp.path()).expect("discover");
let graph = TaskGraph::build(&workspace).expect("graph");
let frontier = graph.frontier();

assert_eq!(frontier[0].task.lane, "up-next");
assert_eq!(frontier[0].task.title, "Queued");
assert_eq!(frontier[1].task.lane, "v0.1.0");
assert_eq!(frontier[1].task.title, "Release Bar");
}

#[test]
fn completed_backlog_cards_satisfy_blockers_without_becoming_open() {
let tmp = tempfile::tempdir().expect("tempdir");
Expand Down
16 changes: 14 additions & 2 deletions crates/method/tests/status_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,14 @@ use method::workspace::MethodWorkspace;

/// Helper: scaffold a valid METHOD workspace in a temp dir.
fn scaffold(root: &std::path::Path) {
for lane in &["inbox", "asap", "up-next", "cool-ideas", "bad-code"] {
for lane in &[
"inbox",
"asap",
"v0.1.0",
"up-next",
"cool-ideas",
"bad-code",
] {
fs::create_dir_all(root.join(format!("docs/method/backlog/{lane}"))).ok();
}
fs::create_dir_all(root.join("docs/design")).ok();
Expand Down Expand Up @@ -54,16 +61,21 @@ fn status_counts_lane_files() {
touch_md(&asap.join("PLATFORM_bar.md"));
touch_md(&asap.join("DOCS_baz.md"));
touch_md(&tmp.path().join("docs/method/backlog/inbox/idea.md"));
touch_md(
&tmp.path()
.join("docs/method/backlog/v0.1.0/KERNEL_release_bar.md"),
);

let ws = MethodWorkspace::discover(tmp.path()).expect("discover");
let report = StatusReport::build(&ws).expect("status");

assert_eq!(report.lanes.get("asap"), Some(&3));
assert_eq!(report.lanes.get("v0.1.0"), Some(&1));
assert_eq!(report.lanes.get("inbox"), Some(&1));
assert_eq!(report.lanes.get("up-next"), Some(&0));
assert_eq!(report.lanes.get("cool-ideas"), Some(&0));
assert_eq!(report.lanes.get("bad-code"), Some(&0));
assert_eq!(report.total_items, 4);
assert_eq!(report.total_items, 5);
}

// ── Active cycle detection ──────────────────────────────────────────
Expand Down
104 changes: 83 additions & 21 deletions docs/BEARING.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,23 @@ code, the code wins and this file should be corrected.
The WARP paper-to-Echo noun map is maintained in
`docs/design/warp-optic-implementation-map.md`.

The feature bar for the eventual `v0.1.0` release is maintained in
`docs/design/v0.1.0-release-plan.md`.

The filesystem lane for release-bar backlog cards is
`docs/method/backlog/v0.1.0/`.

## Current Bearing

Echo already has deterministic execution; it does not yet have a continuous
witnessed intent pipeline into that execution.
Echo has a local witnessed intent pipeline into deterministic execution:
application ingress can become witnessed submission history, lawful admission
evidence, ticketed runtime ingress, scheduler-owned handler dispatch, receipt
correlation, and observable intent outcome.

The current priority is to finish the path from application ingress to
scheduler-owned tick outcome without giving application code tick authority.
The current priority is to make that pipeline consumer-grade for
Wesley-compiled contract packages: contract-aware receipts, honest reading
identity, bounded retained readings, and external consumer proof fixtures
without moving application nouns into Echo core.

## What Is Already True

Expand Down Expand Up @@ -66,11 +76,18 @@ scheduler-owned tick outcome without giving application code tick authority.

## What Is Not Yet True

- Accepted submissions are not yet complete witnessed ingress history.
- Clients cannot yet observe per-intent applied/rejected application semantics
by id.
- Contract-host packaging does not yet reject unsupported contract operations at
an installed registry boundary.
- Accepted submissions are not yet durable restart-proof ingress history;
current replay records prove deterministic import shape, not persistence.
- Product-facing clients do not yet have polished ABI/helper surfaces for
per-intent applied/rejected semantics.
- Contract-aware receipt and reading identities are not yet strong enough for
serious external consumers: package identity, schema identity, operation
identity, basis, vars, aperture, and residual posture need explicit evidence
where the current generic surfaces are too broad.
- Contract artifacts, witness material, and bounded reading payloads are not yet
retained through a generic semantic lookup layer above `echo-cas`.
- External consumer proof fixtures, especially `jedit`, have not yet proven the
generic host path with application-owned contracts and generated artifacts.

## Doctrine

Expand Down Expand Up @@ -190,22 +207,67 @@ AdmissionTicket + witnessed submission -> ticketed runtime ingress
paper-level privacy/runtime policy concepts. The local contract-host pipeline
does not yet implement that full social lane model.

## Immediate Next Slice
## Next Five Slices

1. **Contract-Aware Receipts And Readings**

Make scheduler receipt correlation and QueryView readings honest about the
installed contract package they came from. The first slice should inventory
existing identity inputs and add only the missing generic ones: package
identity, schema hash, artifact hash, operation/query id, basis, vars digest,
aperture or residual posture, and witness refs where needed.

Do not add consumer-specific receipt fields or duplicate identities already
covered by `intent_id`, `ReceiptCorrelationRecord`, or `ReadingEnvelope`.

2. **Contract Reading Identity And Bounded Payloads**

Harden generated-query readings so the identity names the question actually
answered, and bounded observers can return only the requested aperture or a
typed residual/budget posture. This is the read-side counterpart to the
installed intent pipeline.

Do not canonicalize text-editor state in Echo core and do not let CAS content
hashes stand in for semantic reading identity.

3. **Contract Artifact Retention In `echo-cas`**

Add minimal generic retention for contract artifacts, receipt material,
witness refs, reading envelopes, and reading payloads. CAS remains
content-only; semantic lookup keys live above it and include contract/schema
coordinates.

Do not build distributed storage, proof-carrying retention, or app-specific
indexes in this slice.

4. **Contract Retention And Semantic Lookup Seams**

Add the host seam needed for bounded observers and large retained payloads:
contract payloads can refer to retained fragments, observers can read bounded
retained ranges under budget, and unavailable retention returns typed
obstruction instead of fake success.

Do not redefine wormholes, make full materialization canonical, or collapse
retention identity into raw CAS hashes.

5. **External Contract Proof Fixture**

Prove the generic host path with an externally owned Wesley-compiled contract
fixture, with `jedit` as the serious consumer shape. The fixture may exercise
text-like operations and readings, but Echo core must remain generic and free
of text, rope, buffer, editor, or Graft-specific APIs.

The local installed-contract intent pipeline now reaches scheduler-owned handler
dispatch and replay convergence. The next slice should move outward to the
contract-aware receipt/reading and consumer-proof boundary: prove an external
Wesley-compiled contract package can use the generic installed mutation and
query surfaces without moving application nouns into `warp-core`.
Do not build the product UI, author the `jedit` contract in Echo, or add a
special `jedit` ABI.

Direct `native_rule_bootstrap` registration remains an internal fixture and
transitional engine-test path. It does not provide package identity, registry
verification, or generated operation/package binding guarantees. Contract-host
proofs that need those guarantees should install through the package boundary.
transitional engine-test path. Contract-host proofs that need package identity,
registry verification, or generated operation/package binding guarantees should
install through the package boundary.

That next slice must not implement streaming subscriptions, hidden retry,
execution outside scheduler-owned ticks, wall-clock cadence semantics, or
jedit/text-domain APIs inside Echo core.
These slices must not implement hidden retry, execution outside
scheduler-owned ticks, wall-clock cadence semantics, app-controlled tick
authority, or application-domain APIs inside Echo core.

## Do Not Regress

Expand Down
Loading
Loading