Release 3.0.0 (major) — outstanding work integrated; breaking bundle in progress#52
Open
tachyon-beep wants to merge 141 commits into
Open
Release 3.0.0 (major) — outstanding work integrated; breaking bundle in progress#52tachyon-beep wants to merge 141 commits into
tachyon-beep wants to merge 141 commits into
Conversation
Co-authored-by: tachyon-beep <544926+tachyon-beep@users.noreply.github.com>
- Add missing `aria-label`s to `×` icon-only `<button>` tags within dynamically rendered HTML across `detail.js`, `files.js`, `graph.js`, and `workflow.js`. - Fixes accessibility gaps where screen reader users would not be able to discern the purpose of the buttons. - Documented findings in `.Jules/palette.md`. - Ran `pnpm lint:fix` and `pnpm format` which applied cleanups in the JS files as well. Co-authored-by: tachyon-beep <544926+tachyon-beep@users.noreply.github.com>
- Add missing `aria-label`s to `×` icon-only `<button>` tags within dynamically rendered HTML across `detail.js`, `files.js`, `graph.js`, and `workflow.js`. - Fixes accessibility gaps where screen reader users would not be able to discern the purpose of the buttons. - Documented findings in `.Jules/palette.md`. - Ran `pnpm lint:fix` and `pnpm format` which applied cleanups in the JS files as well. - Fixed a failing unit test `test_graph_api.py::TestGraphFrontendContracts::test_topology_change_reuses_positions_only_when_all_nodes_have_positions` which asserted string equality on `Object.prototype.hasOwnProperty.call`, which was auto-linted to `Object.hasOwn()`. Co-authored-by: tachyon-beep <544926+tachyon-beep@users.noreply.github.com>
Bumps [starlette](https://github.com/Kludex/starlette) from 0.52.1 to 1.0.1. - [Release notes](https://github.com/Kludex/starlette/releases) - [Changelog](https://github.com/Kludex/starlette/blob/main/docs/release-notes.md) - [Commits](Kludex/starlette@0.52.1...1.0.1) --- updated-dependencies: - dependency-name: starlette dependency-version: 1.0.1 dependency-type: indirect ... Signed-off-by: dependabot[bot] <support@github.com>
Wardline opens and reopens tracked issues from findings but never closed them when the code was fixed and re-scanned: the absent-fingerprint sweep only visited files present in the batch, so fixing the last/only finding in a file (clean file, absent from `findings`) left the finding open and the linked issue open. Consume Wardline's `scanned_paths` (the authoritative scanned-file set, including clean files) and drive the sweep off the union of files-with-findings and scanned_paths, then fire a close cascade from ingest symmetric to the existing reopen-on-regress cascade. - scanned_paths: optional, wire-compatible request field on POST /api/loom/scan-results (and the classic/living aliases). With it non-empty, mark_unseen=true + findings=[] is now a valid fully-clean scan instead of a 400. Unknown clean paths are skipped (lookup, not upsert). - Close cascade: best-effort, own BEGIN IMMEDIATE, the done-category guard preserves terminal human decisions, failures ride out in warnings (the wire) plus per-failure logs. - Sibling-open guard: never close an issue while another linked finding is still an active defect (checked under the writer lock); also protects the clean-stale path (shared tx). Same-batch regressed issues are excluded from the close so reopen wins over close. Tests (no clean-stale call): no-decoy headline (fix the only finding in a file -> issue closes), mixed file, reopen-after-close, human-decision preserved, idempotent-with-clean-stale, no-spurious-close, fully-clean scan, unknown path no-op, sibling-open, same-batch collision, plus API-layer round-trip / validation / back-compat. Contract fixture + CHANGELOG updated. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…otes Bundled in-flight loom-feedback work on the cross-product entity-association (ADR-029) surface, carried in the working tree alongside the close-on-fixed cascade: - db_entity_associations: document the two-axis freshness/orphan model per ADR-017 — Filigree owns the content axis (freshness_status); the identity axis is Clarion's, so the non-orphaned value is "unknown", never "active". - db_base / db_entity_associations: declare `_skip_begin` on the add_entity_association protocol stub and its @_in_immediate_tx-decorated implementation, matching the convention of the other tx-wrapped methods (reopen_issue et al.) so the stub-signature contract test and the mypy override check agree. - dashboard detail view: only badge a known content-axis freshness state on the forward (issue->entity) lookup, which never carries Clarion's current hash. - doctor: document the deliberate check-id collapse in the machine summary (failed wins, fixed only when nothing under that id failed). - tests: promote-finding-and-attach-entity coverage incl. retry convergence after an attach failure. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…overy Port the security-relevant half of the abandoned anchor-discovery-hardening branch (190 commits stale; its other hardening — permission/decode/empty-gitdir handling — already landed in the refactored `_read_gitdir_pointer`, and its import of `find_filigree_anchor` predates the rename to `find_filigree_conf`). The one genuinely-missing control: `_main_worktree_from_git_path` redirected to a main worktree on the strength of the worktree's `.git` pointer alone, without checking git's bidirectional linkage. A spoofed `.git` file (shipped in an untrusted clone, aimed at a victim project's `worktrees/<name>` admin dir) or a stale pointer (admin dir renamed, worktree removed but `.git` file lingering) would silently redirect discovery onto the wrong project's database. Now verify the admin dir's `gitdir` back-pointer resolves back to *this* `.git` file before redirecting; on mismatch or read failure, `.git` stands as a boundary. This also tightens `_classify_git_entry` (its second call site): a spoofed pointer now classifies as a plain gitdir_file, not a worktree_pointer. Test fixtures now write the back-pointer git always creates on disk (the prior skeleton omitted it, which is why HEAD could drop the check without failures). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…file manifest - pyproject 2.3.0 -> 3.0.0 (major boundary for the deferred breaking wire work) - CHANGELOG: promote merged work to [3.0.0] with a major-release preamble that states the breaking items are tracked in the PR and land incrementally - docs/plans/2026-06-05-3.0.0-release-plan.md: archive/rename/update/create file manifest + breaking-work checklist + the instruction-file untracking note Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… Unreleased header - .jules/bolt.md + .Jules/palette.md rode in via the bolt/palette merges; they are bot learning notes, not release content, and the .jules vs .Jules case-only difference collides on case-insensitive filesystems. - CHANGELOG had an empty [Unreleased] directly above [3.0.0] - Unreleased. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The loom federation hub at ~/loom is now the single authoritative source for federation-wide patterns (roster, axiom, identity model, contract index, URI-scheme status). Filigree retains authority over its own surface (HTTP generations, route shapes, MCP tools, schema, contracts). This commit adds pointers to ~/loom for the stale roster/axiom framing while preserving all Filigree-owned route/envelope/contract definitions: - ADR-002: roster pointer note (was "Clarion/Wardline/Shuttle/filigree"; now 5 members per ~/loom/doctrine.md, Shuttle a thought-bubble); refreshed the stale loom-doctrine reference. Generation decision kept. - docs/federation/contracts.md: authority note + roster framing point to ~/loom/doctrine.md and ~/loom/contracts-index.md. Endpoint/envelope specs (incl. classic /api/issue/... entity-association routes) unchanged. - README.md: added a Loom-federation pointer to ~/loom; kept product copy. - loom-uri-spec.md + planning-deprecation.md: noted loom:// federation status now lives at ~/loom/uri-scheme.md (closed, superseded by SEI; shuttle:// unresolved as Shuttle has no repo). Specs preserved. - shuttle-design.md: roster/status pointer (extra doc found restating the federation member set). ADR-029 internals untouched (Filigree-owned; loom points to it). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ands
INVALID_TRANSITION errors told callers to "Use get_valid_transitions() to
see allowed transitions" — a deferral that named the wrong surface for a CLI
caller and the *old* MCP tool name (renamed to workflow_transition_list). The
non-JSON CLI path prints only the message, so this was the sole information a
terminal user saw. And `close` swallowed the computed valid_transitions in its
generic ValueError arm, emitting a bare envelope unlike update/release/start.
Two fused defects, fixed at the leverage point — lower layers state facts
(reachable target states, no tool name); each surface adds its own affordance:
- db_issues/templates: inline the allowed states into the rejection message
("Allowed from 'fixing': verifying."), degrading cleanly for terminal states.
Drops the stale get_valid_transitions() reference. Shared formatter added as
types.api.allowed_transitions_clause.
- close CLI: route InvalidTransitionError through _transition_error_payload so
the structured valid_transitions/hint flow through both single-id and batch
envelopes, matching its sibling commands.
Audit ("look across all commands") — also inline the other genuine deferrals
where the answer was locally computable:
- unknown-pack (MCP + CLI guide): list real pack/type names.
- scanner-not-found (MCP + CLI list): list the bundled scanner names.
Left as-is (legitimate, not laziness): tool docstrings cross-referencing
sibling tools; doctor/init escape hatches in fatal states.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
CLAUDE.md was removed from the repo in 55e709d ("Removed agents files") but test_live_docs_do_not_reference_old_mcp_tool_names still listed it in LIVE_AGENT_DOCS, so the docs-contract suite went red with FileNotFoundError. The live agent-facing docs now live in instructions.md + the filigree-workflow skill (still covered). Drop the dead entry and fix the comment's file count (9 docs - CLAUDE.md = 8; 2 observe-exempt -> "other 6"). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ree-81d3971467 Schema v24 (verified_actor on event-bearing tables) + CLI OS-user + MCP-stdio parent attribution; session-level identity on FiligreeDB; record-both-and-warn on mismatch. Keystone schema change the other 3.0.0 breaking tickets build on. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Adds verified_actor/verified_author to events, file_events, annotation_events, comments, observations. Nullable, no backfill; events dedup index unchanged. ADR-012. Output shape tracks schema mechanically (SELECT * -> dict(row)), so the observation read path surfaces verified_actor and the create-return literal stamps it None to keep create==list shape; ObservationDict and the CLI shape contract move with it. Value-stamping is a later task. 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>
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>
…tions (ADR-012) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ADR-012 Task 5 follow-up) CommentRecord gained a required verified_author field in b9de64e but the dashboard POST-comment route's response literal was not updated, breaking the full-package mypy gate. Read the stored value back so the response is truthful regardless of whether this route stamped the column. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
comment_to_mcp spreads the full CommentRecord, so the v24 verified_author column now rides along on the MCP comment result. Update the stale contract assertion. Loom federation surface is unaffected (explicit adapter). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…cascade (ADR-012) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
_merge_into_survivor collapsed a duplicate (issue_id, locator) binding into the (issue_id, sei) survivor but carried only content_hash_at_attach + attached_at — never the Legis sign-off columns. Deleting a signed non-survivor row dropped its signature, silently downgrading the issue governed->ungoverned (DECISION 1A), after which the closure gate short-circuits to PROCEED with no Legis call. Carry the freshest valid sign-off onto the survivor (signed wins, never downgrade, higher signoff_seq when both signed), mirroring the v27 upsert stickiness in db_entity_associations. Even in the content-mismatch edge the result is governed-but-STALE -> fail-closed, so no path silently PROCEEDs. Guard tests: signed non-survivor carries forward; signed survivor not downgraded by an unsigned incoming; freshest signoff_seq wins both directions. filigree-c31a22fd47 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The "3.0.0 tool names" admonition backticked the removed flat aliases (get_issue, list_findings, start_work) to explain the rename, which tripped the doc guards (test_no_markdown_doc_names_an_old_tool and test_live_docs_do_not_reference_old_mcp_tool_names) and reddened the suite. Drop the inline old-name list — the new names stay, and the full old->new table is the migration guide's job (MIGRATION-3.0.md, which the guards do not scan). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The doc-example linter joined backslash continuations but not open-quote continuations, so a `filigree` example whose quoted argument spans newlines (valid shell, e.g. a multi-line -d "..." body) was captured as an unbalanced-quote fragment and skipped — its verb/options escaping drift-checking. Three real examples were silently unguarded. Extract the per-doc parsing into _command_lines_in_text and keep consuming raw lines until the quotes balance (or the block ends, preserving the skip safety valve for genuinely malformed examples). The three previously-skipped examples now assemble, validate, and pass (67 passed, 0 unparseable skips). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The module-level comment still flatly claimed the server-mode .mcp.json "is written 0600", contradicting the runtime fix (0134f59) that stats and reports the real mode because chmod is a best-effort no-op-returning-success on filesystems like WSL DrvFs / CIFS. Reword to "chmod-tightened toward 0600 (best-effort)" so the prose matches the behaviour — the last residue of prong 3. filigree-ebfc16a090 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… probe
Two silent best-effort paths in the store/install surface now log when they
fail for a real reason, instead of hiding a hygiene gap:
- migrate_store_to_weft: the legacy-husk federation_token unlink was wrapped in
contextlib.suppress(OSError). missing_ok=True already absorbs the absent-file
case, so any OSError reaching the suppressor is a real failure (e.g.
PermissionError) that leaves a now-dead per-machine secret behind with zero
signal. Warn so the operator can clean it up.
- _git_tracks: an inconclusive ls-files probe (raised exception, or a non-{0,1}
return code such as 128 "not a repo" / index-lock contention) was
indistinguishable from a clean "not tracked" (rc 1) answer, silently silencing
the "already-tracked -> git rm --cached" token warning the caller derives from
it. Log both inconclusive cases at debug.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The editable filigree pin in the lockfile still read 3.0.0rc9 after the version bump landed in 7bcc6c3; resync it to rc10. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
READ_ONLY_CODEBASE_AUDIT_2026-06-04*.md were git-tracked and shipped in the 3.0.0 sdist (~79KB of internal agent audit notes reaching published consumers; the wheel was already clean). git rm --cached both and add a .gitignore pattern so they stay local-only. Files remain on disk. Closes filigree-107e275ab3 (PR #52 epic, B6). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Both file_events import INSERTs (merge + non-merge) listed verified_actor but omitted actor, so an export->import round-trip silently reset the claimed actor to '' even though write paths (register_file(actor=...)) stamp a real value and export dumps it. Add actor to both INSERTs; the merge dedup identity (WHERE NOT EXISTS) is unchanged. Audit-trail fidelity fix, not a security hole — actor is the self-claimed identity; the trustworthy verified_actor already round-tripped. Tests: two new round-trip assertions (non-merge + merge) in test_verified_actor.py, verified red-then-green. Closes filigree-673a1f3af5 (PR #52 epic, B4). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The bearer-auth middleware (dashboard_auth) is built on Starlette 1.0 BaseHTTPMiddleware/Request semantics, but the floor floated via fastapi, whose requires-dist is starlette>=0.46.0 (unbounded). uv.lock pinned 1.0.1 for in-repo CI, but published-wheel consumers resolve from pyproject and a future re-lock could cross the 0.x->2.x boundary and break auth. Declare the constraint directly; lock unchanged (1.0.1). Closes filigree-d57e5a5b66 (PR #52 epic, W2). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ent (T4) These three modules carry the Legis closure-gate, transport-bound actor identity, and governance-client logic but had no per-module floor, so a single-module coverage collapse could hide under the aggregate 85% gate. Add explicit FILE_FLOORS a few points below measured (actor_identity 95, governance 90, legis_client 85). Closes filigree-d8156e627b (PR #52 epic, T4). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
check_closure_gate attached the LEGIS_API_TOKEN bearer to a plain urllib request whose default redirect handler copies request headers onto the redirect target with no same-origin check, so a 302 from a compromised or open-redirecting Legis could re-send the token to an attacker host. Route the request through a custom opener whose redirect handler drops Authorization before following a redirect (benign redirects still follow; normal non-redirect token auth unchanged), and refuse a non-http(s) LEGIS_URL before attaching the bearer or making any request. Defense-in-depth: exploitation needs a Legis-side open-redirect or a compromised Legis, not a critical on its own. Tests (TDD, red-then-green): two-server redirect->sink harness in tests/_fakes/legis_http.py; test_redirect_does_not_leak_bearer_token, test_non_redirecting_gate_still_sends_token, test_non_http_scheme_refuses in test_legis_client.py. ruff + mypy clean; CHANGELOG Security entry. Closes filigree-93c1d49f2a (PR #52 epic, B3). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…_id (FIL-2/X-5)
finding_list's filters were flat top-level columns — no way to exclude
wardline's kind:metric engine telemetry (158 of 160 findings in the live
store) or baselined/suppressed defects. To answer "show me the real
un-suppressed defects" an agent had to pull every finding and filter nested
metadata.wardline.* client-side. Wardline's producer-side `scan where:{}`
grammar already filtered with more power than its consumer.
Port the relevant axes onto finding_list as flat params (consistent with
filigree's API style; functional parity, not JSON-shape parity):
- kind — metadata.wardline.kind enum (defect/fact/classification/metric/suggestion)
- suppression — active|baselined|waived|judged over metadata.wardline.suppression_state;
active = the un-suppressed population
- qualname — metadata.wardline.qualname (exact match)
- rule_id — the conspicuously-missing top-level column filter
Headline query: `finding_list kind=defect suppression=active`.
Wired through the single chokepoint (db_files.list_findings_global) so every
surface gets parity: MCP finding_list tool + handler + ListFindingsArgs, CLI
list-findings (--kind/--suppression/--rule-id/--qualname), HTTP
GET /api/weft/findings, and the /files/_schema discovery endpoint. sink/tier
skipped (absent at the filigree<-wardline seam); path_glob deferred (weft-2b71565563).
The suppression=active predicate is the SAME shared SQL helper
(_wardline_suppressed_sql) as unbridged_finding_stats' "actionable" split, so
the active/suppressed classification cannot drift — though the populations
differ (unbridged_finding_stats also restricts to open+unbridged, so its count
is a subset). json_valid guards corrupt-metadata rows from OperationalError;
absent/corrupt verdict reads as active.
Also fixes a pre-existing connection leak surfaced by the new tests' GC
pressure: the mcp_surface fixture in test_cross_surface_parity.py was a
`return db`-style fixture that never closed its sqlite connection, tripping the
suite's -W error ResourceWarning gate non-deterministically. Converted to
yield + close (mirrors the sibling dashboard_surface fixture).
Tests: core/MCP/CLI/HTTP filter coverage incl. corrupt-metadata, the
shared-predicate classification vs population-superset distinction, and qualname
at every surface. ruff/format/mypy clean; full suite green under
-W error::ResourceWarning.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Review nit: test_redirect_does_not_leak_bearer_token asserted only that the SINK saw no Authorization, so in isolation it couldn't distinguish "bearer stripped at the redirect" from "bearer never sent". The redirect (origin) server now records the Authorization it received, and the test asserts the bearer DID reach the origin (hop 1) but did NOT cross to the sink — proving the strip happens precisely at the redirect boundary without relying on the companion non-redirect test. Test-only; no production change. Follows up filigree-93c1d49f2a (B3). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…igree-2bdb878bd2)
Residual of the wardline->filigree N2 seam (weft-171fc22a50). A plain finding
work-query (`finding_list` / `list-findings`) returned wardline-baselined/
waived/judged findings mixed with real ones at status:open severity:high --
annotated via suppression_state but not hidden -- so `finding_list status=open
severity=high` still surfaced already-accepted defects as fresh, open work.
Both agent surfaces now default to suppression='active'; pass suppression='all'
to include suppressed rows, or a specific verdict to triage them. The
default-hide lives at the agent surfaces ONLY:
- core list_findings_global keeps its all-inclusive default (suppression=None);
internal callers (e.g. scanner_reporting re-finding a just-ingested row) are
unaffected.
- 'all' is a new accepted suppression value = explicit no-filter sentinel (no-op).
- the federation read API (GET /api/weft/findings) and the dashboard (per-file
/files/{id}/findings) are deliberately UNCHANGED -- machine/human read
surfaces whose consumers pass an explicit suppression= filter; guarded by a
regression test so a sibling's machine-read contract is never silently
narrowed.
Complements the already-shipped finding_promote suppression guard and the
session-context actionable/suppressed split. Seam verified against wardline's
to_filigree_metadata: metadata.wardline.suppression_state in
{baselined,waived,judged}, absent => active.
Tests: surface default-hide + 'all' opt-in + literal ticket repro
(status=open severity=high) on MCP/CLI; core 'all' no-op + default-stays-all
contract lock + off-contract non-dict metadata.wardline + pagination-after-
filter; API capability advertises 'all' + federation-default-stays-inclusive
guard. Docs: CLI/MCP reference + CHANGELOG.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…tract F7 (filigree-2bdb878bd2) Names the deliberate read-surface asymmetry so it is a contract, not an implicit behaviour: agent surfaces (MCP finding_list / CLI list-findings) default suppression=active; the machine/federation surface (GET /api/weft/findings) defaults to all (inclusive); the dashboard (per-file) is unchanged. Documents that suppression_state is a first-class top-level field on ScanFindingWeft — consumers filter via ?suppression= or the top-level field and must never reach into the member-specific nested metadata.wardline blob. Records the reversal trigger: the machine surface stays inclusive-by-default until a real consumer wants default-hide there. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… server mode (filigree-b62d865dad) An unscoped classic-router write (POST /api/issues) in server mode silently resolved to the daemon's default project: ProjectMiddleware set no project ContextVar, _get_db fell back to default_key, and the X-Filigree-Project echo was gated behind is_loom_scoped_path — so the misroute was undetectable. Broaden the echo to every non-/mcp response (scoped branch echoes the resolved key, unscoped branch echoes default_key), uniform with the federation read seam. The federation-write fail-closed stays is_federation-gated and untouched — classic writes are NOT failed closed because the dashboard's no-project default view legitimately writes to /api and relies on default resolution. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…tring (filigree-a4925b59bb) server.json entries are keyed by store-dir string, but a project's identity is its root. A .filigree -> .weft/filigree store relocation re-registered under the new store dir while the old key lingered with the same prefix, so the collision check read it as a conflict and raised ValueError, refusing the move. Dedup by project root via the existing anchor-based _project_root_from_store_dir helper: any existing entry resolving to the same root is the same project's stale key, so drop it instead of colliding. Converges to a single live key and self-heals. A running daemon's in-memory project_store is out of scope — this fixes the durable server.json record; the daemon reconciles on next reload. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ee-197be8b501) Step 2's metadata sub-tree copy (scanners/, templates/) used shutil.copytree straight to the final path, guarded on `not dest.exists()` — the same torn-then-skip pattern already fixed for the DB copy and the metadata files: a crash mid-copytree leaves a PARTIAL directory at the destination that a re-run's existence guard mistakes for a finished copy and skips, publishing the partial. Add _atomic_copy_tree (copytree into a dest-dir temp, then os.replace) so dest only ever appears complete; a crash leaves only the temp (cleaned up), and the copy-once guard stays but is now safe because a present dest is always finished. Regression test simulates a crash mid-copytree and asserts no partial is published and a re-run re-copies the complete tree. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…c6958f31) An ad-hoc writer (a fresh CLI/MCP process) that opened the legacy DB AFTER the daemon detect-and-refuse check passed and committed during the copy→unlink window had that commit orphaned on the about-to-be-unlinked inode. The daemon refuse handles long-lived idle connections; this closes the complementary active-writer case. Hold BEGIN IMMEDIATE on the legacy DB across the whole snapshot→conf-rewrite→ unlink window (_migration_write_fence): BEGIN IMMEDIATE excludes all other writers, so no foreign commit can land between the snapshot and the unlink, and a writer already holding the lock makes acquisition raise StoreMigrationBusyError before any mutation (superseding + widening the old copy-time checkpoint-busy guard). The DB copy switches from checkpoint+file-copy to the SQLite online- backup API (_snapshot_copy_sqlite_locked), which folds WAL-resident commits and preserves the FILG application_id without a checkpoint — checkpointing cannot run under the fence (it self-conflicts / returns busy). Backup runs from a fresh reader, never the fence holder (that hangs). Empirically validated: backup-under- sibling-fence completes + preserves data/app_id, the fence blocks a 3rd writer, and unlink-under-fence + rollback/close is clean (POSIX open-fd semantics). Removes the now-unused _checkpoint_and_copy_sqlite; updates the WAL-fidelity test rationale and the crash test to target the new backup/atomic-publish seam; adds TestMigrationWriteFence (fence blocks concurrent writer, refuses on held writer, locked snapshot preserves WAL+app_id). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…pth, not a full close (filigree-39c6958f31) Systematic-debugging follow-up: a discriminating thread test showed the fence RELOCATES the ad-hoc-writer data-loss rather than eliminating it. A writer that opens the legacy DB and blocks on the fence during the sub-second hold, with a busy_timeout longer than the hold (FiligreeDB sets 5s), commits to the orphaned inode AFTER the fence releases and the legacy files are unlinked — silently lost (POSIX keeps an open fd writing to a deleted inode; the migration cannot stop a writer it does not cooperate with). No behaviour change — the fence is still worth shipping as defense-in-depth: it refuses migration when a writer is ALREADY active at acquire (StoreMigrationBusyError, superseding the copy-time checkpoint-busy guard) and gives short-/zero-timeout writers a visible SQLITE_BUSY. But the prior commit's docstrings/comments overclaimed 'no foreign commit can land' as a closure. Correct them to state the known residual plainly and credit the MANDATORY operator quiesce (docs/UPGRADING.md) + daemon detect-and-refuse as the real backstops — the ticket's own option 3. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… fixes (filigree-197be8b501, filigree-39c6958f31) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… page Adopt the Weft Federation "Loom" design system as a full re-skin of the Filigree docs site, and add a narrative page documenting Filigree's role in the federation and how it engages each member. - Re-vendor the canonical shared docs theme (loom-mkdocs.css -> weft-mkdocs.css): warm espresso ground + dyed-amber accent, per-member thread palette. Filigree keeps its sky thread (#56B7E2) as its member accent. extra.css repainted onto the warm ramp. - Rebuild overrides/home.html: hero corrected to 116 MCP tools (was 114), the old "Loom Federation suite" grid replaced with a Weft Federation roster (Loomweave/Filigree/Wardline/Legis/Charter, Filigree "you are here", Lacuna adjacent-note). Sibling links point at repos (only wardline.foundryside.dev resolves; clarion/legis/charter subdomains 404). - New docs/federation/index.md "Filigree in the Weft Federation": role as work-state surface, the two structural facts (SEI LOCKED 2026-06-05, stored opaque; weft generation as additive-only transport per ADR-002), per-member bindings each with its caveat carried verbatim (Wardline-> Filigree A-1 LIVE), and the anti-claims (no weft:// scheme, no broker). - Fix invisible primary-CTA label: Material's `.md-typeset a` color out-specified `.fg-btn--primary`, painting it sky-on-sky. Raise the button color selectors' specificity; verified in dark + light. - copyright.html footer: "Loom suite" -> "Weft Federation"; Clarion -> Loomweave. mkdocs build --strict green. Docs-only; no source changes. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ree) The legacy .filigree/ store was the stale-key source behind the federation emit drift (weft-7436c1959e, C2 root cause). With the canonical .weft/filigree store registered on the shared :8749 daemon and emit verified (findings land in .weft/filigree, not here), the legacy dir is retired. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…(filigree-c3e2b72f21) Every FindingsSummary producer (get_file_findings_summary, get_files_findings_summary, get_global_findings_stats, and the inline list_files_paginated / loom file-list summary) bucketed severity by open status alone, so a baselined HIGH was indistinguishable from an active HIGH and federation consumers over-reported actionable high/critical work by the count of already-accepted findings. Additive fix: the existing top-level buckets keep their meaning (every open finding, suppression-agnostic) and a parallel `suppressed: SeverityBreakdown` is added, computed with the same shared classifier as the row-level finding_list suppression filter so the two cannot drift. Consumers derive actionable work as `bucket - suppressed[bucket]`; no existing number changes. GlobalFindingsStats and EnrichedFileItem.summary inherit the key. Counterpart of weft federation interface audit gap G4. (CHANGELOG entry for this change lands with the following commit, which shares the file.) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…fig.json (filigree-4bf16e64b6) Completes the WEFT store consolidation for config the way migrate_store_to_weft did for the database. The project anchor moves off the legacy root file .filigree.conf into the store's own config.json (the sole-writer subtree). - filigree init imports a present conf into .weft/filigree/config.json (conf-wins on prefix/enabled_packs/registry_backend/loomweave/project_name; mode stays config.json-authoritative; db dropped) and retires it to .filigree.conf.imported — idempotent, crash-convergent (config.json written atomically before the conf is atomically renamed). Fresh installs are born confless. - New anchor = presence of .weft/filigree/ (or a weft.toml [filigree].store_dir override, now discoverable via a new resolve_store_dir-based anchor rung). weft.toml is never written by filigree and never holds identity (C-9c deletion test: filigree boots with no weft.toml). - find_filigree_anchor gains include_legacy_dir=True; the three implicit-startup surfaces (generate_session_context, the agent dashboard hook, stdio-MCP with no --project) pass False so a bare legacy .filigree/ ancestor is still not treated as attach-consent. The .git-boundary ForeignDatabaseError guard is preserved. - Legacy .filigree/ STORE reads stay (resolve_store_dir back-compat, C-9f); only the conf ANCHOR is demoted to one-shot-import-and-retire. Existing installs migrate on their next init; nothing breaks until then. - config.json is now the sole identity authority, so from_store_dir is STRICT on a present-but-corrupt config.json (raises VALIDATION at open, symmetric with from_conf) instead of silently defaulting to the dir name — which would fragment issue IDs across two prefixes. A missing config.json stays lenient. Also authors filigree's half of the shared weft.toml schema (docs/federation/), to be merged with loomweave-009 at the weft hub, plus a drop-in sibling-adoption prompt. CHANGELOG carries both this entry and the G4 entry from the prior commit. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
3.0.0 — major release train
Opens the SemVer-major boundary to land the deferred breaking wire-surface
changes that could not ship mid-2.x without breaking federation consumers
(Clarion / Wardline / Shuttle). Draft until the breaking checklist below is
complete and a consumer-migration window is published.
Full plan + file manifest:
docs/plans/2026-06-05-3.0.0-release-plan.md.Already landed (this PR so far)
codex/loom-feedback-ticketsscanned_paths; ADR-029 entity-association polish; doctor contractsbolt-opt-issue-batch-querypalette-aria-labelsdependabot/uv/starlette-1.0.1fix/anchor-discovery-hardeningCI gate (merged branch): ruff ✓ · ruff format ✓ · mypy (105 files) ✓ · pytest (full, 4 skips) ✓ · biome JS ✓.
Loomweave / Weft rebrand (landed — 7 commits, schema v26)
The full federation-contract rebrand (epic
filigree-1d08ffb493) landed as thelast bundle on this branch. Hard wire-break, no compatibility aliases (owner
decision) — Filigree was the last federation member still on the old names;
Loomweave/Wardline/Legis had already cut over.
57dd00513a2331generations/loom→generations/weft(by-identifier)e5fd2d1clarion_entity_id→loomweave_entity_id(column/PK/index) + rewrite every storedclarion:eid:→loomweave:eid:SEI prefix (entity_associations,deleted_issuesF5 tombstone array, entity-association audit events) +CLA-→LMWV-rule-ids7941702SEI_PREFIX→loomweave:eid:081675eregistry_backend/[clarion]→loomweave+ one-shot rename-on-load config shim56e2ec6/api/loom/*→/api/weft/*,protected_paths, path-scope auth,CLARION_LOOM_TOKEN→WEFT_TOKENd1bfcd1[3.0.0], docs, CI lane names, contract fixtures, dashboard JSVerification: ruff · ruff format · mypy (109 files) · biome JS ·
make coverage-floorsall ✓. Full suite green except one pre-existing flaky observations concurrency test (test_concurrent_create_returns_existing_under_dedup_race, passes in isolation). Brand sweep clean modulo intentional migration/shim references;weftweavesubstring tripwire clean.Operational (deploy-time, not code — need an owner):
WEFT_TOKENin every deployment env (CLARION_LOOM_TOKENis no longer read).loomweave:eid:entity_ids (T0bfiligree-2cf022fff2). Stored signatures are stale-pending-reissue by design; Filigree never verifies them, so reads do not break.Note: "Task 7" (token audience loom→weft) is a no-op in Filigree code — the federation bearer token is opaque (
hmac.compare_digest), with no audience/JWT claim. The hub mirror~/weft(sei-standard.md/contracts-index.md) was updated toloomweave:eid:out-of-band (separate repo, uncommitted).Intentionally NOT renamed (quarantined — hub hasn't locked them,
filigree-73a2d91f5c): registry error codesCLARION_REGISTRY_VERSION_MISMATCH/CLARION_OUT_OF_SYNC, theloom://URI scheme, the capabilities probe, the Legis surface name.Cosmetic residuals (non-blocking follow-up): test-infra file/dir renames (
test_clarion_*.py,tests/_fakes/clarion_http.py,tests/fixtures/contracts/loom/),api_loom_*handler function names +is_loom_scoped_path, bareloomprose in src docstrings, and historical ADR bodies (kept per "don't rewrite shipped ADRs").mainfix/anchor-discovery-hardeningwas 190 commits stale. Most of its hardening(permission/decode/empty-gitdir handling) already landed in
main's refactored_read_gitdir_pointer, and it importedfind_filigree_anchor— a symbol sincerenamed to
find_filigree_conf. Forcing the cherry-pick would have imported deadsymbols and resurrected superseded inline code. Instead, the one genuinely
missing control — bidirectional worktree back-pointer verification (anti-spoof /
anti-stale-pointer) — was re-implemented fresh against current code, with focused
TDD tests (
0fd7e3d). You're getting one security control, not a whole branch.Breaking-work checklist (required before this leaves draft)
filigree-7771610917— MCP tool namespacing (~115 tools) + dual-resolution alias window (ADR-016) — largest; ripples to all consumersfiligree-45d76e71bb— De-Clarionize entity-association naming (compat alias) (in_progress; partially merged)filigree-e4181ae767— Remove deprecatedget_statsalias keysfiligree-9b4bb6e52e—TransitionModeenum replacingbackwardboolfiligree-d25e75cebf—safe_messageparity for claim/transition errorsfiligree-81d3971467— Transport-bound actor identity verification (likely the schema v24 bump)Docs to create/update before release
get_statskey migration,entity_idrename)docs/UPGRADING.md,docs/MIGRATION.md,docs/mcp.md,docs/api-reference.mddocs/plans/completed/Note: instruction-file untracking (out of scope, left in working tree)
The filigree instruction-manager rewrote
.gitignoreand untrackedAGENTS.md/CLAUDE.mdthis session. Deliberately kept out of thesecommits — adopt or revert as a separate decision.
🤖 Generated with Claude Code