Skip to content

feat: capability ladder Rung 0/1/2 — temporal-correlation spine + COP internals#1

Merged
tachyon-beep merged 10 commits into
mainfrom
feat/rung-0-1-2-capability-ladder
Jun 16, 2026
Merged

feat: capability ladder Rung 0/1/2 — temporal-correlation spine + COP internals#1
tachyon-beep merged 10 commits into
mainfrom
feat/rung-0-1-2-capability-ladder

Conversation

@tachyon-beep

Copy link
Copy Markdown
Contributor

Implements the reviewed plan at docs/plans/2026-06-16-rung-0-1-2-implementation-plan.md — the base-impl stabilization plus the temporal-correlation spine internals. Built on the ratified contract (hub PDR-0025) sponsoring warpline's temporal-episode axis.

How this was produced

  • Design (ultracode): map → specialist design (refactoring / sqlite-schema / api-architect) → reality + architecture + doctrine review → synthesis.
  • Build-readiness review (ultracode, round 2): caught a runtime NameError (_EDGES_FOR_COMPLETENESS) and that Track B was unbuildable (no wardline resolved-finding surface). Verdict resolutions are authoritative in the plan's round-2 section.
  • Build (ultracode): 8 sequential tracks, each behind the full gate, committed individually.

What's in (8 commits)

  • Rung 0 — behaviour-preserving split of commands.py (959→771 LOC) into _enrichment.py + _blast.py.
  • Rung 1a — ordered, forward-only migration runner + PRAGMA hardening (user_version gate, atomic BEGIN IMMEDIATE per step).
  • Rung 1b — working-context anchor columns (schema v2): detected_branch/head_sha/at + detected_context (clean|working_tree_dirty|detached_head). The change-episode axis, orthogonal to SEI.
  • Rung 1c — self-healing SEI re-resolution sweep (reresolve.py + reresolve-sei CLI; idempotent merge of null-keyed rows).
  • Rung 1d — always-on lazy edge-snapshot capture (pure blast_radius preserved; hook + doctor checks). No new inputSchema field.
  • Track C — lights up the previously-inert risk/governance reverify enrichment (honest present|absent|unavailable).
  • Track A — temporal co-change coupling graph (schema v3, after v2 per the ordering gate; fan-out cap + WARPLINE_COCHANGE kill-switch).
  • Track Dcop.py COP internals (resolve_frame over rev_range/sei/time_window/edit/branch_sha + compose_temporal_cop with coverage/dark-sectors) + a non-frozen internal warpline cop demo CLI.

PDR-0025 acceptance

tests/integration/test_reconstruction_demo.py exercises a real squash-merge fixture (N commits collapsed to one new mainline SHA, branch deleted) — reconstructs via SEI frame, degrades honestly with weft_reason_class on rev-range, branch_sha fallback stays useful. 3/3 pass.

Verification (independent, on the branch)

  • ruff clean · mypy --strict clean (33 files) · pytest 263 passed (was 166) · wardline scan --fail-on ERROR exit 0 (0 active findings).

Explicitly NOT in scope

  • Track B (verification freshness) — deferred; no wardline resolved-finding/timestamp surface exists (cross-member ask).
  • Public MCP/CLI COP tool wiring — interface-pending (awaiting the concrete public surface); cop.py internals + the non-frozen demo CLI are ready for it to drop onto.
  • Version bump / CHANGELOG — these are additive 1.1.0-class capabilities; deferred to a release PR per plan E6, and the "next version" call is still owner-open.

Doctrine

Enrich-only, never-gating; SEI never minted/parsed; no sibling data mirrored (read-time compose); honesty invariant throughout; no frozen v1 contract mutated (all additive). Per PDR-0025 cond 3 the spine sits behind the launch cutover in priority — this branch is ready but not a launch-cutover dependency.

🤖 Generated with Claude Code

tachyon-beep and others added 10 commits June 16, 2026 00:19
…MO proposal adopted

Capture the Warpline capability ladder (Rung 0-4) as the roadmap backbone, the
temporal-correlation spine and its consumer surface (the temporal common operating
picture), and the PMO proposal that took the spine to the foundation.

- roadmap.md: capability ladder; correlation spine RATIFIED (hub PDR-0025); the COP
  read surface; PM conditions inlined (squash-merge demo, episode ~= work-session,
  sequencing fence behind launch cutover + base impl).
- PDR-0002: adopt the capability ladder as roadmap backbone.
- PDR-0003: relay the hub ruling (PDR-0025) sponsoring warpline's temporal-episode
  axis into warpline's decision log, with all three PM conditions.
- PMO proposal (adopted): §7 corrected — SHA-rewrite (squash/rebase) is distinct
  from rename (PDR-0021); the rename feed carries no rewrite reconciliation.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Execution plan for the capability-ladder work, produced by a multi-agent design
workflow (map -> specialist design -> reality/architecture/doctrine review ->
synthesis) and hardened by a second adversarial build-readiness review.

- Folds PDR-0025 conditions: squash-merge reconstruction demo as the load-bearing
  acceptance criterion, episode ~= work-session, sequencing fence behind launch.
- Owner-session enhancements E1-E6 (demo deliverable, fence, full verification
  gate incl. wardline, dirty-tree honest fallback, co-change kill-switch, 1.1.0).
- Round-2 resolutions (authoritative): fix a Rung 0 NameError blocker
  (_EDGES_FOR_COMPLETENESS), DEFER Track B (no wardline resolved-finding surface),
  pin migration v2<v3 ordering, Rung 1d always-on (no inputSchema field), plus
  ~20 reality/sequencing fixes.

Build-ready for base-impl tracks; COP public surface remains interface-pending.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Behaviour-preserving decomposition of commands.py: characterization tests
first, then extract the pure staleness/completeness helpers into
warpline._enrichment and the blast-pipeline prep helpers into warpline._blast.

- _enrichment.py: EDGES_FOR_COMPLETENESS + is_stale/edges_enrichment/
  staleness_warnings/completeness_warnings. Import-free except typing.Any
  (structurally incapable of gating). is_stale uses int(behind) (R2).
- _blast.py: rev_range_commits/resolve_changed_inputs/enrich_blast with a
  private strict-assert _as_int. WarplineStore is always a parameter.
- commands.py 959 -> 771 LOC (<800, M1). capture_snapshot keeps using
  EDGES_FOR_COMPLETENESS (B1); _as_int and the 2 rev_range_commits sites
  stay (M2). Zero change to the 7 tool signatures, 6 SCHEMA_* constants,
  cli.py, mcp.py behaviour.
- Lift _init_repo/_commit into tests/conftest.py (conftest-helper minor).
- New characterization suites: test_enrichment_helpers.py (incl. B1 dict
  access) + test_blast_helpers.py.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Establish a real ordered, forward-only migration runner in store.py as the
prerequisite gate for all schema work (Rung 1b v2 anchors, Rung 2 v3
co-change). The runner is established here with an empty MIGRATIONS list
(highest known version stays 1); v2/v3 land in later tracks.

- Connection hardening: foreign_keys=ON, busy_timeout=5000, synchronous=NORMAL
  (WAL retained via SCHEMA executescript fresh-DB note).
- SQLite >= 3.35 floor, justified by the RETURNING clause in
  create_edge_snapshot (no migration drops a column).
- Per-step BEGIN IMMEDIATE / COMMIT with conn.execute only (never
  executescript) so user_version + meta update atomically (R3).
- Concurrent open() re-reads user_version under the RESERVED lock and skips
  already-applied steps (idempotent, no double-apply).
- M9 reconcile: user_version==0 with meta.schema_version=='1' adopts 1;
  with a divergent meta value, warn + adopt it before later steps.
- user_version > highest-known: warn to health_log, reads stay safe, no fail.
- SCHEMA DDL is FROZEN after Rung 1a (all change via MIGRATIONS).
- test_store.py BOTH schema_version()==1 assertions intentionally left at 1
  (they flip to ==2 when v2 lands in Rung 1b, not here).

Add tests/test_store_migrations.py.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…1b, schema v2)

Migration v2 adds detected_branch, detected_head_sha, detected_at, and
detected_context (clean|working_tree_dirty|detached_head, M8/E4) to
change_events — the working-context anchor for the DETECTION act, orthogonal
to the SEI and never on entity_keys.

git.py ingest_commit computes the anchor once per call and threads it onto
every change_event it writes; backfill records all anchor columns NULL (B3:
reconstruction is not detection). store.append_change_event takes optional
anchor kwargs; list_change_events and timeline surface the new columns.

Updates both test_store.py schema_version assertions to ==2 and reconciles the
Rung 1a migration-runner tests to a non-empty MIGRATIONS list (highest known
version 2). Adds tests/test_anchor_capture.py covering branch/dirty/detached
detection, the B3 backfill all-NULL rule, the store read surface, the v1->v2
migration, and the M10 additive-column non-regression for change_list /
entity_timeline.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add the idempotent UPDATE-or-merge core that heals entity keys minted while
loomweave was unavailable (sei IS NULL). store.null_sei_entity_keys pages the
worklist; store.reresolve_entity_key_sei repoints in place, or on a
resolved-sei twin collision repoints change_events, DELETEs null-keyed
duplicate events (resolved-keyed row canonical, M5/R11), deletes the orphan
null key, and carries min(first)/max(last) seen onto the survivor.

reresolve.sweep_reresolve_sei orchestrates per-locator resolution and reports
the loomweave posture explicitly (present|absent|unavailable); client=None is a
pure no-op that never marks a key resolved-to-null. The reresolve-sei CLI verb
drives it and is NON-FROZEN/internal (not one of the six frozen v1 tools).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ung 1d)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…e reconstruction demo (Rung 2 Track D)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d5edbc36f3

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/warpline/commands.py
repo,
client=client,
source_version=source_version,
scope_locators=scope_locators or None,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Avoid marking scoped lazy snapshots as full

When the first impact_radius/reverify call on a cold store has resolved seed IDs, this passes only those seed locators into capture_edge_snapshot; that helper still records the snapshot as FULL unless there are failures or caps. As a result, a depth>1 traversal can miss edges beyond the seed neighborhoods, and later queries for other entities skip recapture while reporting edges: present/completeness: FULL over a partial graph. Either capture the full graph here or make scoped captures surface as partial and not suppress future captures.

Useful? React with 👍 / 👎.

Comment thread src/warpline/store.py
Comment on lines +903 to +905
ON CONFLICT(repo_id, entity_key_id_a, entity_key_id_b) DO UPDATE SET
co_change_count = co_change_count + 1,
last_co_change = excluded.last_co_change,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Keep co-change counts idempotent per commit

If the same commit is ingested/backfilled more than once, append_change_event is idempotent but this conflict handler still increments co_change_count again for the existing pair. That makes warpline backfill reruns or repeated ingest-commit HEAD calls inflate coupling counts and confidence without any new co-change commit; the upsert needs to distinguish an already-counted last_commit_sha (or track commit-pair membership) instead of always adding one.

Useful? React with 👍 / 👎.

Comment thread src/warpline/store.py
Comment on lines +602 to +603
# Delete the now-orphaned null key (its events were repointed/merged).
self.conn.execute("DELETE FROM entity_keys WHERE id = ?", (null_key_id,))

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Repoint co-change pairs when merging SEI twins

When a null-SEI key collides with an already-resolved twin, this deletes the null key after repointing change_events, but any co_change_pairs rows that were written for the null key remain keyed to the deleted id. In the normal hook order (ingest-commit writes pairs, then reresolve-sei heals), those orphaned pairs disappear from co_change_partners for the surviving entity and can also make the other partner skip the missing key, so the coupling graph loses historical co-change evidence unless the pair rows are merged/rebuilt in the same transaction.

Useful? React with 👍 / 👎.

Comment thread src/warpline/cli.py
store.log_health(args.repo, "HOOK_INGEST_FAILED", str(exc))
return 0
if args.command == "loomweave-probe":
if args.command == "reresolve-sei":

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Restore the loomweave-probe CLI branch

This new reresolve-sei branch replaced the old if args.command == "loomweave-probe" guard but left the probe payload after a return, so invoking warpline loomweave-probe --json now falls through to the top-level help with exit 0 instead of probing loomweave. The parser still advertises the subcommand, so callers and doctor-style diagnostics get no probe result until the loomweave-probe handler is restored as its own branch.

Useful? React with 👍 / 👎.

Comment thread src/warpline/install.py
# Managed by Warpline. Fail-soft by design: Warpline must never block commits.
{executable} ingest-commit HEAD >/dev/null 2>&1 || true
{executable} reresolve-sei --limit 25 >/dev/null 2>&1 || true
{executable} capture-snapshot --commit HEAD >/dev/null 2>&1 || true

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Keep full captures out of the commit hook

In repos where loomweave is installed and indexed, this hook now runs capture-snapshot synchronously on every git commit; the CLI defaults to a full capture, which probes loomweave and can query every stored entity neighborhood before the commit command returns. That violates the hook's own fail-soft/non-blocking contract for nontrivial repos even though the exit code is swallowed, so the capture should be made bounded/backgrounded or left to the lazy read path instead of running full in post-commit.

Useful? React with 👍 / 👎.

# added the reresolve-sei + capture-snapshot lines (install.py:hook_body); an
# older installed hook lacks them, so `doctor` flags it stale and `--fix`
# reinstalls (R5 — editing hook_body alone never rewrites installed hooks).
HOOK_CURRENCY_SENTINEL = "reresolve-sei"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Check every current hook line in doctor

The doctor currency check only looks for reresolve-sei, so a managed hook that has that line but is missing the new capture-snapshot line is reported as current and doctor --fix will not repair it. In that stale-hook state commits keep ingesting/re-resolving but never capture snapshots, which is exactly the newly added hook behavior doctor is meant to enforce; make the sentinel require all current managed commands or compare against the generated block.

Useful? React with 👍 / 👎.

Comment thread src/warpline/store.py
Comment on lines +685 to +690
if since is not None:
clauses += " AND ce.changed_at >= ?"
params.append(since)
if until is not None:
clauses += " AND ce.changed_at <= ?"
params.append(until)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Normalize timestamps for time-window filters

The new COP time_window path filters changed_at with string comparisons, but the stored values come from git %aI and can include arbitrary timezone offsets. For events authored outside UTC, lexicographic ordering can include changes before since or exclude changes before/after until incorrectly (for example 2026-01-01T00:30:00+02:00 sorts after a UTC since even though it is earlier in absolute time), so these bounds need to compare normalized instants rather than raw text.

Useful? React with 👍 / 👎.

Comment thread src/warpline/store.py
Comment on lines +602 to +603
# Delete the now-orphaned null key (its events were repointed/merged).
self.conn.execute("DELETE FROM entity_keys WHERE id = ?", (null_key_id,))

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Repoint snapshot edges when merging SEI twins

The same null-key merge also leaves snapshot_edges rows pointing at the deleted entity id. If a snapshot was captured before the SEI later resolves to an existing twin, impact_radius seeded with the survivor cannot traverse edges whose source/target is still the orphaned id, so affected-set results lose previously captured graph evidence until a full recapture happens; merge or rewrite those snapshot edges in this transaction before deleting the null key.

Useful? React with 👍 / 👎.

Comment thread src/warpline/store.py
"""

repo_id = self.ensure_repo(repo)
self.clear_co_change_pairs(repo)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Honor the co-change kill switch during rebuild

rebuild_co_change_pairs clears the existing graph before replaying commits, but the replay path now honors WARPLINE_COCHANGE=0 by skipping every write. Running warpline rebuild-coupling in an environment that disabled live co-change writes therefore deletes all existing coupling data and replaces it with an empty graph; check the kill switch before clearing, or make rebuild a no-op when writes are disabled.

Useful? React with 👍 / 👎.

@tachyon-beep tachyon-beep merged commit d5edbc3 into main Jun 16, 2026
4 checks passed
tachyon-beep added a commit that referenced this pull request Jun 24, 2026
…0006

Records the accept+ship decision (14-agent adversarially-verified review, verdict
ship, 0 blockers/majors; verified-minor findings deferred to 4 tracked follow-ups).
Roadmap: hardening out of Now (shipped); verification-freshness sole active Now bet.
Metrics: 2026-06-24 reading for the 1.2.0 ship. Escalation #1 (merge+1.2.0) resolved;
#2 (hub handover) carries forward.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant