Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
02aa7f0
docs+test: rename federation sibling Charter -> Plainweave (live refs)
tachyon-beep Jun 24, 2026
a211fda
plan: verification-freshness (Rung 2 Track B) implementation plan
tachyon-beep Jun 25, 2026
8d316a7
plan: address review v1 (4 blockers, 1 high, 5 medium) — verification…
tachyon-beep Jun 25, 2026
9b4dfa1
plan: address review v2 (4 high, 5 medium) — verification-freshness
tachyon-beep Jun 25, 2026
b1236af
plan: review v3 APPROVED (0 blocker/high/medium); fold in GV-VF-1 nex…
tachyon-beep Jun 25, 2026
688531d
feat(store): v4 verification_events table + key-id-filtered change ac…
tachyon-beep Jun 25, 2026
f24bc58
refactor(store): scope v4 recovery to presence-floor reconcile path
tachyon-beep Jun 25, 2026
85b992d
feat(git): is_ancestor / commits_between / resolve_commit reachabilit…
tachyon-beep Jun 25, 2026
60d5fde
feat(verification): pure compose_verification_freshness (fresh/stale/…
tachyon-beep Jun 25, 2026
51e29ef
test(verification): lock unavailable/stale contract + cover earlier-u…
tachyon-beep Jun 25, 2026
998b3b7
feat: verify-record verb (CLI + MCP, 2nd mutating tool)
tachyon-beep Jun 25, 2026
e87df23
docs: correct verify-record enrichment defaults; pin empty-kind error…
tachyon-beep Jun 25, 2026
fc6f369
feat(reverify): advisory per-item verification block + summary + stal…
tachyon-beep Jun 25, 2026
4511b6a
test: prove same-depth stale-first tiebreak in reverify ordering
tachyon-beep Jun 25, 2026
9b7ec5b
test(contracts): GV-VF-1 locks verification-freshness honesty + never…
tachyon-beep Jun 25, 2026
763dd8a
test(contracts): fix GV-VF-1 vector count (19) + lock honesty-meta on…
tachyon-beep Jun 25, 2026
5e593b7
docs(changelog): verification freshness (Rung 2 Track B)
tachyon-beep Jun 25, 2026
5503031
fix: four review follow-ups before merge (latent crash + doc + tests …
tachyon-beep Jun 25, 2026
b68f0c4
fix(verification): stale decay uses tightest git cover, not recording…
tachyon-beep Jun 25, 2026
ddba775
fix(snapshot): preserve prior FULL/DELTA when loomweave absent at rec…
tachyon-beep Jun 25, 2026
3f6f652
test(contracts): carry enrichment_reasons in frozen-envelope fixtures…
tachyon-beep Jun 25, 2026
7683407
fix(honesty): weft-reason invariant survives python -O (assert -> Val…
tachyon-beep Jun 25, 2026
9d21d0d
site: member-specific deconfliction-not-security disclaimer + Charter…
tachyon-beep Jun 26, 2026
fe9d51b
product: 1.2.0 follow-up burndown (fc09bdeddd + d88e223731 closed); r…
tachyon-beep Jun 26, 2026
a554726
feat(federation): D1 impact_completeness self-assessment on reverify_…
tachyon-beep Jun 26, 2026
e33b3c5
feat(federation): Rung-2 wardline-attest-2 consumer (risk-as-verifica…
tachyon-beep Jun 27, 2026
5944b24
feat(federation): wire the attest-2 consumer into reverify (CLI + MCP)
tachyon-beep Jun 27, 2026
f147d60
fix(attest): build the content_hash map from the FULL worklist, not t…
tachyon-beep Jun 27, 2026
2cc0ebe
feat(federation): wire the legis governance_read.v1 consumer into rev…
tachyon-beep Jun 27, 2026
461640c
test(federation): cover the capability-gated legis wiring through _h_…
tachyon-beep Jun 27, 2026
e6a66b4
chore(federation): re-mirror legis governance_read.v1 (hardened discr…
tachyon-beep Jun 27, 2026
7fbefb4
fix(federation): align legis governance-read invocation to the shippe…
tachyon-beep Jun 27, 2026
e4c7816
feat(mcp): add read-only project_status store-binding probe
tachyon-beep Jun 27, 2026
4b94705
Merge plan/verification-freshness into release/1.2.0
tachyon-beep Jun 27, 2026
def6d43
chore(git): Ignore wardline scan results.
tachyon-beep Jun 27, 2026
e2b8ccc
chore(release): working-set checkpoint — honesty/ergonomics fixes + a…
tachyon-beep Jun 28, 2026
5ef2472
docs(arch-analysis): add temp working notes (debt + validation catalogs)
tachyon-beep Jun 28, 2026
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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,4 @@ findings-rust.jsonl
.mcp.json
loomweave.yaml
weft.toml
.wardline
118 changes: 118 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,124 @@ The cross-member MCP seam contracts are versioned independently as
`warpline.<contract>.v1` and frozen at the federation clean-break launch; a `v2`
is a new contract URI, never a mutation of `v1`.

## [Unreleased]

### Added
- **`warpline_project_status_get` / `project_status` — read-only store-binding
probe (`warpline.project_status.v1`).** A new MCP tool that reports whether THIS
build can read and *serve* the snapshot store for a given `repo`
(`data.binding_ok`), reading `schema_version` **from inside** the store — never
mere directory existence — so a stale-but-running warpline that cannot read its
`.weft/warpline` store at a compatible schema is caught (the federation
attachment signal Lacuna's `make verify` harness asserts on). It is the first
**genuinely** read-only tool: `writes_local_state: false`, `mutates_paths: []`,
and it creates/migrates **no snapshot state** — an absent store reports
`store_status: store_absent` with a `capture_snapshot` next-action (no DB is
created), a corrupt store `store_unreadable`, and a store written by a newer
build `schema_ahead` (all three: `binding_ok: false`, `schema_version: null`);
a present store's `warpline.db` is left byte-for-byte unchanged. Reads the store
strictly read-only (`mode=ro`, no create-on-missing; opening a present WAL store
may spawn gitignored `-wal`/`-shm` coordination sidecars, which are not snapshot
state). The frozen
six-tool federation-contract inventory (`mcp-tool-inventory.json`) is unchanged
— this is an additive health probe, not a frozen data contract.
- **legis governance read consumer (`governance_read.v1`).** `reverify
--include_federation` now lights up the previously-inert `legis` member with a
real `LegisGovernanceClient` over the `legis governance-read <SEI>` verb
(output is always JSON; matched to legis's shipped CLI, no `--json` flag),
consuming legis's authoritative `governance_read.v1` (verified clearances only:
operator override / cleared sign-off). Mirrored BYTE-FOR-BYTE as the source of
truth at `contracts/governance_read.v1.schema.json` (legis OWNS it; warpline
echoes advisorily and NEVER gates — `GV-LG-1`, no `governance_verdict` in
output). The mirror tracks legis's hardened discriminated union (`unavailable` ⇒
non-empty reasons + empty `records`; `checked` ⇒ no `unavailable` key) — a
backward-compatible tightening, pinned by consumer-side rejection tests so an
`unavailable` answer can never masquerade as a clean empty.
The clearance `content_hash` is echoed verbatim, NOT re-derived against the current
body (governance is an echo, not a warpline-asserted verdict — contrast the
attest-2 path). Honesty: an empty read is `governance: absent` = "no verified
clearance," which deliberately conflates *ungoverned*, *unknown-SEI*, and an
entity **actively BLOCKED awaiting sign-off** — so `absent` is never
"ungoverned" (disclosed in the schema + the federation reference docs). Wiring
is **capability-gated**: the client is wired only when the installed legis
advertises `governance-read`; until then the member is honestly `disabled`
(capability absent), not a forced `unreachable`, and lights up automatically
once legis ships the verb. The `governance_read.v1` schema vectors are the
contract's canonical samples, not a live capture (the read surface is unshipped
at time of writing).
- **Risk-as-verification: wardline-attest-2 consumer (Rung 2).** Closes the
`verification_source_absent` gap D1 left open. warpline now consumes a PUSHED,
UNTRUSTED `wardline-attest-2` evidence bundle and, for a worklist whose impact
set is genuinely `complete`, reads **proven-good** iff EVERY affected entity is
attested clean at its CURRENT body — mechanical `(commit, content_hash)`
equality per SEI against the bundle's boundaries (`verdict == "clean"`, not
`dirty`, commit pins, content_hash matches loomweave's per-entity body hash).
The body hash is sourced from the SAME loomweave `entity_resolve` round trip
warpline already uses for the SEI (`resolve_content_hash_for_locator`); it is
byte-identical to the value wardline binds into the bundle (verified across
loomweave's MCP `entity_resolve` and HTTP `/api/v1/identity/sei` surfaces). The
verdict is an **echo of wardline's authority, signature NOT verified by
warpline** (`authority: "wardline"`, `signature_verified: false`) — never a
warpline-minted clean. Every honesty edge (no bundle, non-attest-2 schema,
dirty tree, null/mismatched commit, `sei_source: "unavailable"`, null sei /
content_hash, non-clean verdict, ANY unmatched affected entity) degrades to
`unavailable` with an explicit machine reason; proven-good is all-or-nothing.
Pure consumer (`_attest.worklist_risk`); layered on D1's completeness gate.
WIRED on the real surfaces: `warpline reverify --attest-bundle <file>` (CLI) and
the `attest_bundle` MCP arg ingest the pushed bundle; the verdict is emitted at
`data.risk_verification` on EVERY worklist (without a bundle it honestly reads
`verification_source_absent`). The per-SEI current content_hash is fetched from
the same loomweave `entity_resolve` round trip warpline already makes
(fail-soft). Documented in `contracts/reverify_worklist.v1.schema.json`.
- **Impact-completeness self-assessment (federation D1).** The reverify worklist
now carries an additive `data.impact_completeness` object —
`{status: complete|partial|unknown, as_of, graph_fresh, graph_ref, depth_capped,
unresolved_count, reasons[]}` — warpline's honest verdict on whether the impact
set is exhaustive for the change. One object declares BOTH axes: the staleness
axis (`as_of` producer timestamp + `graph_fresh` + `graph_ref`) and the
completeness axis (`status` + `depth_capped` + `unresolved_count`).
`status="complete"` is emitted ONLY when the graph is positively fresh (FULL,
`commits_behind==0`), the blast traversal hit no depth cap, and zero changed
entities were unresolved; any gap → `partial`; no graph at all → `unknown`.
Never `complete` on a guess. A new `depth_capped` signal in the blast traversal
honestly reports when a depth-bounded scope left reachable impact unexplored.
This is the field downstream consumers (wardline mirrors it verbatim into
`producer_completeness`) rely on to NOT treat a narrowed scope as authoritative.
Published as a drift-checkable contract artifact at
`contracts/reverify_worklist.v1.schema.json` (JSON Schema, draft 2020-12), which
validates real worklist output. Consumer side (risk-as-verification): an absent
or non-`complete` assessment degrades warpline's own risk path to
`risk=unavailable` with an explicit reason (`completeness_not_declared` /
`completeness_partial`) — never `clean`. Additive on `.v1`: the FROZEN raw
snapshot-completeness `data.completeness` STRING enum is unchanged (raw signal
vs. derived assessment); no `v2` bump.
- **Verification freshness (Rung 2, Track B).** The reverify worklist now carries
an advisory per-item `verification` block (`fresh` / `stale` / `unverified` /
`unavailable`) with a trust-decay signal, plus a `verification_summary` rollup —
answering "what changed since it was last proven good." Sourced from warpline's
own gate result via a new mutating verb `verify-record` (CLI) /
`warpline_verification_record` (MCP), the 2nd local-only mutating tool. Advisory
and enrich-only: it annotates and re-sorts (stale-of-trust first) but NEVER
filters an item, and NEVER gates. Sibling-sourced verification (wardline/
filigree/legis) remains honest-absent RESERVED. New schema v4
(`verification_events`); golden vector `GV-VF-1`. The frozen `warpline.<contract>.v1`
envelope and the closed 6-key enrichment vocab are untouched (verification rides
the reverify-item schema, not the enrichment vocab).

### Fixed
- **Weft-reason honesty invariant now survives `python -O`.** `listing.reason()`
enforced its carrier rule (class-membership, and "every non-clean carrier MUST
carry both cause and fix") with bare `assert`s, which `-O` strips — so under
`-O` a hollow `{reason_class: "disabled"}` triple with no cause/fix could ship,
the exact unexplained-absence the honesty doctrine forbids. Promoted both checks
to raised `ValueError`, and hardened `build_envelope` to reject a non-clean
`enrichment_reasons` triple missing cause/fix (closing the parallel
hand-built-via-kwarg path, which bypassed `reason()` even without `-O`).
`sei_reason()` is now non-Optional — it raises on an out-of-vocab state, which
removed four `-O`-strippable narrowing asserts at its call sites. Internal
hardening only; the frozen `warpline.<contract>.v1` envelope and the closed
enrichment vocab are unchanged.

## [1.2.0] - 2026-06-24

Minor release: spine hardening. Snapshot capture is now correct-by-construction and
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ never decides whether a change is allowed.** This is deconfliction tooling, not
security. A warpline answer is an enhancement you can act on or ignore — never a
verdict you must clear. It **consumes** Loomweave SEI (it never mints identity) and
**feeds** advisory change-impact facts to governance-style surfaces such as
Legis/Charter, which run their own policy; warpline supplies the facts and never
Legis/Plainweave, which run their own policy; warpline supplies the facts and never
makes the call.

The product front door lives at
Expand Down
91 changes: 91 additions & 0 deletions contracts/governance_read.v1.schema.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://weft.dev/contracts/governance_read.v1.schema.json",
"title": "legis governance_read.v1",
"description": "Per-SEI VERIFIED GOVERNANCE CLEARANCE facts produced by legis (the governance authority) and consumed advisorily by siblings (e.g. warpline reverify enrichment). v1 reports verified clearances ONLY (operator overrides + cleared structured/protected sign-offs). 'records: []' under status 'checked' = no verified clearance for this SEI on legis's verified trail -- NOT 'ungoverned', and NOT 'unknown SEI' (legis is an SEI consumer, never the SEI authority; it cannot distinguish unknown-from-ungoverned). status 'unavailable' = legis could not produce a signature-verifiable answer (no protected gate / verifier / key); consumers MUST treat it as 'unavailable', NEVER as 'absent'. A TAMPERED trail does not reach this envelope at all -- it fails loud as a transport-level integrity error (MCP AUDIT_INTEGRITY_FAILURE / HTTP 5xx / CLI nonzero exit).",
"type": "object",
"required": ["status", "sei", "records"],
"additionalProperties": false,
"properties": {
"status": {
"description": "Envelope state. 'checked' = the verified trail was read (records may be empty = honest absence of clearance). 'unavailable' = could not produce a signature-verifiable answer.",
"enum": ["checked", "unavailable"]
},
"sei": {
"description": "The SEI queried, echoed verbatim. Opaque; never parsed.",
"type": "string",
"minLength": 1
},
"records": {
"description": "Verified governance clearance records keyed on this SEI. Empty under 'checked' = honest absence. Always [] under 'unavailable'.",
"type": "array",
"items": { "$ref": "#/$defs/clearance_record" }
},
"unavailable": {
"description": "Present ONLY under status 'unavailable' (and required there): why legis could not produce a verifiable answer. Non-empty.",
"type": "array",
"minItems": 1,
"items": {
"type": "object",
"required": ["reason"],
"additionalProperties": false,
"properties": { "reason": { "type": "string", "minLength": 1 } }
}
}
},
"allOf": [
{
"if": { "properties": { "status": { "const": "unavailable" } }, "required": ["status"] },
"then": {
"required": ["unavailable"],
"properties": { "records": { "maxItems": 0 } }
}
},
{
"if": { "properties": { "status": { "const": "checked" } }, "required": ["status"] },
"then": { "not": { "required": ["unavailable"] } }
}
],
"$defs": {
"clearance_record": {
"type": "object",
"required": ["sei", "disposition", "posture", "authority", "as_of", "reasons", "content_hash"],
"additionalProperties": false,
"properties": {
"sei": {
"description": "The SEI this clearance is keyed on (== the SIGNED entity_key.value; identity-stable).",
"type": "string",
"minLength": 1
},
"disposition": {
"description": "Record-level governance disposition. NOT the envelope 'status', NOT a consumer's 'enrichment.governance'. v1 closed enum = {'cleared'}: every record is a verified human clearance. (Future dispositions arrive in governance_read.v2 -- v1 is never mutated.)",
"enum": ["cleared"]
},
"posture": {
"description": "The PROVABLE clearance mechanism. legis does NOT claim the enforcement cell for a sign-off (it cannot prove structured-vs-protected for a cleared sign-off) -- it reports the mechanism it can prove. 'protected_override' = a protected operator-override verdict; 'operator_signoff' = an operator-cleared sign-off.",
"enum": ["protected_override", "operator_signoff"]
},
"authority": {
"description": "Clearing-authority class. v1: both clearance kinds are operator-cleared.",
"enum": ["operator"]
},
"as_of": {
"description": "Timestamp from the SIGNED recorded_at of the clearance record (RFC3339 UTC; '+00:00' and 'Z' both valid). A clearance whose recorded_at is absent or non-RFC3339 is OMITTED by the producer (asymmetric-error rule) -- it never ships as null.",
"type": "string",
"format": "date-time"
},
"reasons": {
"description": "Closed-vocab codes naming the clearance kind (what happened). Never free prose. Distinct axis from 'posture' (the provable mechanism / how); v1 correlates them 1:1 by construction, but v2 may carry additional reason codes without changing posture.",
"type": "array",
"minItems": 1,
"items": { "enum": ["operator_override", "signoff_cleared"] }
},
"content_hash": {
"description": "The SIGNED Loomweave content hash binding the clearance to the governed content (non-empty).",
"type": "string",
"minLength": 1
}
}
}
}
}
Loading