proof: knowledge-layer validation programme (stacked on #18) - #19
Draft
NetDevAutomate wants to merge 61 commits into
Draft
proof: knowledge-layer validation programme (stacked on #18)#19NetDevAutomate wants to merge 61 commits into
NetDevAutomate wants to merge 61 commits into
Conversation
Freeze the SessionWeaver Phase 2 retrofit's spec and design ahead of any Phase B code, per EXECUTION-ERRATA.md correction #3 and council ruling R2 ("acceptance is not spec-check alone"). The design document normatively fixes the cross-machine standing order for replicated concept lifecycle events and its two-copy test matrix, the v48/v49 migration contracts and their rollback strategy, the non-fatal ontology refresh-failure seam, seed sanitization, the byte-for-byte memory_recall contract, the fresh-install scope diagnostic, and the ConceptService compatibility seam -- so B1-B6 can implement against a reviewed contract instead of inventing one under implementation pressure. Delta specs add Gherkin-scenario requirements to six existing capabilities (harness-session-memory, data-store-and-sync, mcp-server, session-export, health-and-diagnostics, configuration-and-secrets); no capability is newly created. openspec validate --specs --all: 25 passed, 0 failed. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…ange - proposal.md: the request_scope() call-site list has eight entries; the source plan mislabels it "seven" (design.md and tasks.md already said eight). - design.md: B3 must test whether the reference allocator's table-wide MAX(logical_time) already satisfies two-copy matrix item 4 before adding an explicit advance-on-import step. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…and diagnostics Lift SessionWeaver's frozen tier-1 ontology extraction/rebuild/status module (extraction version tier1-v2-canonical-messages, same logical-hash algorithm, so A2's baseline stays comparable). Migration v48 installs the six schema objects additively; install_schema is tolerant of a pre-existing ad hoc ontology schema (found on the real sessions.db) so a real upgrade converges instead of crashing -- the first rebuild replaces it regardless of its prior shape. Wire an incremental ontology refresh into export_sessions._run_export, behind a named, monkeypatchable seam (refresh_ontology_after_export) called after the capture commit: a refresh failure is caught, logged as a structured ontology_refresh_failed warning, surfaced in the export summary, and never rolls back captured sessions (EXECUTION-ERRATA.md #7). Add `session-maint ontology-rebuild [--incremental]` and `ontology-status` for manual/maintenance recovery. Add the sync boundary: ontology tables never join SYNC_TABLES or GLOBAL_SYNC_TABLES (positive-control tested), and sync._seed_remote_db strips every ontology row from a seed snapshot before scp so a freshly seeded remote derives its own ontology rather than inheriting the source's. Add a report-only "harness" doctor check (present/coverage/freshness/ extraction-version), never fatal, with a fixture-inserted red-path test. Add the ontology_live safety harness (Online Backup only, real DB never touched, new opt-in live_ontology pytest marker) and R7 migration-safety tests: fresh creation, interrupted-migration recovery, downgrade, and idempotent re-migration. Retains real acceptance receipts (docs/data/) from a live Online Backup run: coverage 100%, zero integrity violations, identical hash across two full rebuilds and one incremental no-op, cold rebuild 3.47s. Fixes a v47-pinned assertion in test_replica_coordinator.py that this version bump would otherwise break, and regenerates .secrets.baseline (detect-secrets 1.5.0) for the two evidence files' SHA-256 hashes. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…ed scope
A virgin install crashed or leaked ad-hoc errors the moment any scope-dependent
path ran: `studyloop study` propagated a bare ScopeError as a generic exit-1
ClickException, each of the seven unguarded request_scope() MCP tool sites let
FastMCP wrap it in ad-hoc text, and session-db-mcp's open_context()/
_get_connection() let sqlite3's "unable to open database file" leak through a
distinct, unhelpful error shape on a database that simply doesn't exist yet.
Add ScopeUnconfiguredError (a ScopeError subclass identifying exactly the
"nothing configured" case) and scope_setup_diagnostic(), one shared
{code: "scope_unconfigured", message, remediation} shape. Every entry point
that can hit it now reports that same payload instead of a traceback: the
CLI exits 2, both MCP servers' tool-call boundaries return isError with the
JSON payload embedded in the text content, and a missing database is treated
identically to a missing scope rather than as its own error class.
Both packages' config writers (generate_default_config(), ensure_config_dir())
now write memory.default_scope: unclassified explicitly for a brand-new
config.yaml, so a fresh install is immediately usable. The runtime default for
an absent file or a file that omits the key stays unset (errata #9) -- this
changes only what a *generated* file contains, not what an absent setting means.
Tests: packages/studyloop/tests/test_fresh_install_scope.py drives a virgin
HOME (no STUDYLOOP_CONFIG, no SESSION_CONTEXT_SCOPE) as a real subprocess
against the source tree -- the CLI, all seven MCP tool sites, and
session-db-mcp's session_search/memory_search -- so this suite's own
config-isolation fixtures cannot hide the defect the way the existing fixture
already did. test_fresh_install_scope_installed.py (marked integration)
repeats every check against a real `uv build` wheel install per plan ruling
R10. Unit tests cover scope_setup_diagnostic, ScopeUnconfiguredError, the two
config writers' round trip, and open_context()/_get_connection() on a missing
database.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Add a "Tier-1 ontology (derived, never synced)" section to docs/session-memory.md covering what it captures, why it never syncs, the automatic export-time refresh, and session-maint ontology-rebuild/ontology-status for manual recovery. Record the feature under CHANGELOG.md's [Unreleased] Added. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Mark tasks.md's B2 tasks 2.1 (migration v48 + lift), 2.2 (refresh hook + session-maint ontology-rebuild), and 2.3 (sync boundary + seed sanitization) complete. Leave 2.4 unchecked with an inline note: its tests/hash/timing/count verification and a green preflight are done, but code/build-ontology.py's retirement is explicitly B6's (task-B2-brief.md) and the independent review is the reviewer's step. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Task B1 of openspec/changes/sessionweaver-phase2-retrofit: generated config writes memory.default_scope: unclassified; one structured ScopeError diagnostic at the CLI and every MCP tool in both servers; missing-database path covered; virgin-HOME tests on source-tree and installed-package paths. Review: .superpowers/sdd/sessionweaver-phase2/task-B1-review.md (0 findings). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…d agents CI run 34167164262 (jobs test (3.12) and test (3.13)) failed test_fresh_install_scope.py::test_studyloop_study_exits_2_with_the_diagnostic_on_a_virgin_home because on the GitHub runner `studyloop study 'Test Topic'` exits 1 with "No AI agent found. Install one of: Kiro CLI, Codex, Claude Code, OpenCode, or pi" before the scope check ever runs. session/start.py calls detect_agents() (studyloop.agent_launcher) before start_study_session() raises ScopeUnconfiguredError, so the expected exit 2 + structured scope diagnostic is unreachable unless some agent binary is resolvable via shutil.which on the subprocess's PATH. Locally the test only passed because this machine has agent CLIs installed. Fix the test, not production code: add a `_fake_agent_bin()` helper that writes a no-op executable named `claude` (matching studyloop.adapters.claude.ADAPTER.binary) into a throwaway bin dir and prepends it to the subprocess PATH via `_usable_path()`/`_virgin_env()`'s new `agent_bin` parameter. detect_agents() only calls shutil.which(), so the script is never actually executed -- start_study_session() still raises ScopeUnconfiguredError immediately after agent selection, well before any launch command is built. Applied to both test_studyloop_study_exits_2_with_the_diagnostic_on_a_virgin_home and its installed-wheel sibling in test_fresh_install_scope_installed.py, which had the same dependency. Reproduced RED locally by running both files with a PATH stripped of every real agent CLI (venv bin + tmux + /usr/bin:/bin only), then confirmed GREEN with that same stripped PATH after the fix. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Replace permission-bit failure injection with the backup helper's real None failure contract. This keeps the abort-before-stream invariant reliable under both ordinary users and root CI containers.
Preserve direct coverage that a nonzero SSH/sqlite command result is translated into None after the push-contract test moved to the orchestration seam.
Bring the independently reviewed migration v48, deterministic ontology evidence, and CI-parity sync test correction into the SessionWeaver Phase 2 integration branch. # Conflicts: # .secrets.baseline # docs/session-memory.md
Lift SessionWeaver's concept_schema.py unchanged (SCHEMA_VERSION = 2, SCHEMA_FINGERPRINT byte-identical to the reference, af95685e6e39e166148006519862bee3be1a15219d76772236a82890fe11011d) and add migrate_v49, which installs exactly that DDL: context_concepts, context_concept_events, context_concept_clock, context_concept_fts and context_concept_schema, plus their indexes/triggers and the two context_citations guard triggers. UPSTREAM_SCHEMA_VERSION is pinned to 49, the migration number that installs the sidecar. Why: tasks.md 3.1 -- B3 owns v49 (v48 stays B2's); the sidecar must be additive-only, with context_assertions.proposed_state left as execution state (errata #3), and adopt a byte-identical pre-existing PoC sidecar while refusing drift, because sidecar rows are authored data. Migration-safety per B2's R7 pattern: fresh create to v49, additive-only shape check on context_assertions, exact-adopt, drift refusal, interrupted-migration recovery, repeated-open idempotence, downgrade contract, and a real Online Backup v47->v49 upgrade retained as docs/data/concept-sidecar-migration-v49-receipt.json (aggregates only; source sentinels asserted unchanged; live DB still v47, 5813 sessions). The detect-secrets baseline is regenerated for the receipt's hex-hash false positives, matching B2's precedent. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…ection Lift SessionWeaver v0.2.0's concepts.py, winddown.py, okf.py (as okf_import.py), projection.py (A3b2's fixed Publisher with its identity-guarded rollback), authorization.py and safe_fs.py into agent_session_tools.context, adapting only import paths to the package (relative imports; okf -> okf_import). All frozen contracts are kept byte-identical: the sessionweaver://session/ source-URI prefix, the session_weaver_projection frontmatter key, the projection marker and manifest filenames, and ConceptService's public surface (project, winddown, transition, bind_legacy, import_okf). Why: tasks.md 3.1 -- B4 consumes ConceptService as a caller, never a second implementation, and B6 deletes the SessionWeaver copies, so the lifted behaviour must be the reference behaviour, provable by the reference's own tests. Tests: the reference suites lifted with the same import rewrites (223 tests: schema exactness/adoption, wind-down parsing, lifecycle transitions, bind closure, OKF scan/classification precedence, projection publish/rollback, adversarial SQL integrity). Two adaptations, both consequences of v49 installing the sidecar up front: the upstream-version pin asserts 49, and a rejected import call now asserts zero sidecar rows instead of no sidecar table. One targeted nosec B506 documents that _StrictSafeLoader narrows yaml.SafeLoader. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Concept roots and their complete append-only event history join the context replication protocol: snapshot selection follows the authorization seam's two visibility shapes (bound roots travel with their assertion's citation closure, legacy roots with their claimed session), the apply path inserts only rows it does not already have, and the receiving side's own schema triggers re-validate every root. The local clock, the FTS read model and the schema marker never travel. Standing is exactly the frozen order (design.md, ruling R2): standing = max(events, key=(lamport, machine_id, event_id)) with machine_id = context_access_state.instance and lamport = logical_time. The three read-model sites drop the reference's standing-kind precedence, which contradicted the frozen pure-triple order under replication ties while being locally unobservable (local lamports are strictly increasing); the lifted total-order test is adapted to the frozen order with the reasoning recorded inline. Duplicate machine_id is diagnosed and refused, never merged: negotiate() already refuses two live peers with one instance, and the new ConceptReplicaIdentityError refuses incoming events that claim the receiver's own instance for history it never wrote, or that bind one (origin_instance, origin_seq) slot to two different events. Lamport advance on import (design.md's B3 verification note): matrix item 4 was run against the unmodified reference allocator first, and passes -- _allocate's table-wide MAX(logical_time) already advances the next local event past every imported lamport, so no explicit advance-on-import step was added. Also wired: v49 adds the three replica-content-generation triggers for the two replicated tables (v46 froze its own list); staged transport indexes both tables by id; the legacy-sync guard treats the sidecar's seeded singletons and FTS shadow tables as bookkeeping, not populated context; tiering's archive-completeness proof excludes the per-database clock and concept-FTS shadow tables while keeping roots/events in the retention proof; compaction seeds a fresh clock/marker and copies roots after their citation closure so the sidecar triggers re-validate. Tests: the normative two-copy matrix (7 scenarios) on fixtures in both replication orders, replay idempotence, post-convergence Lamport advance, read-model hash equivalence, concurrent accept/retire resolved to the computed winner in either order, causal accept-then-retire, and three duplicate-identity refusals; plus the same matrix once on two real Online Backup copies (live_concepts marker, copy B honestly re-identified before any concept history exists, source sentinels asserted unchanged). Full package suite: 1999 passed. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…MCP tool session-context gains winddown --session ID --from FILE|--stdin and concept accept|retire ID --reason, concept bind LEGACY_ID --from FILE --reason, concept import-okf DIR [--dry-run] [--report PATH], and concept project --out DIR [--project ID] [--json], all thin wrappers over the frozen ConceptService seam with the reference CLI's bounded input reading (wind-down byte limit, descriptor-anchored non-symlink files), atomic report writes, deterministic JSON payloads, and the reference exit-code contract (2 validation, 1 runtime/write failure). mcp_server.py gains memory_winddown with the same validation: a field-level error list raises a structured ToolError and writes nothing; a valid batch commits atomically. Why: tasks.md 3.2 -- one seam, one validation surface, no second implementation of concept transitions; context_assertions keeps its execution-state vocabulary (verified in the round-trip test). Also frozen (tasks.md 3.4): ConceptService's public API is pinned by an exact-signature regression test (method set, every signature string, and the four result shapes), so B4 consumes a checked contract. This commit also carries the live_concepts harness extensions and their opt-in tests (they type-check as one unit with the CLI): the live two-copy matrix on two real Online Backup copies, and the full 2,033-record legacy OKF import runner whose sanitized report feeds the OpenSpec evidence attachment. Tests: lossless round trip, stdin input, field-level failures for malformed documents/invalid JSON/symlinked input, lifecycle verbs with retired-terminal diagnostics, legacy bind, OKF dry-run/write/report, projection output, MCP happy path and loud structured failure with zero partial writes. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…evidence docs/context-memory.md gains the wind-down/concept command reference, the two trust labels (model-proposed vs legacy-unbound, never blended), the frozen cross-machine standing order in one paragraph, and the frozen ConceptService surface table. CHANGELOG records the concept sidecar under [Unreleased] Added. OpenSpec tasks 3.1-3.5 are checked with their evidence pointers (3.5's independent review remains the reviewer's step). The evidence file is added with -f: openspec/ is gitignored for new files, but this change's artifacts are tracked and the brief requires the report attached to the change directory. Evidence: openspec/changes/sessionweaver-phase2-retrofit/evidence/ legacy-okf-import-report.json -- the full legacy OKF import on a real Online Backup (live_concepts marker): 2,035 scanned, 2,033 parseable records imported legacy-unbound with zero write failures and the exact A3b1 baseline FTS content hash (0c036eae...); the two extra files are post-baseline non-records classified invalid_schema (reported, never dropped); dry-run/write classification identical; idempotent re-import already_present=2,033 with zero writes; OKF tree sentinel and source database sentinels unchanged. The visibility sub-classification split differs from the baseline because this run retains every project unclassified on a newer corpus (5,813 sessions vs 5,678); the report retains the split (no_exact_match 1559, no_visible_evidence 429, oversized_evidence 45) for the reviewer. The detect-secrets baseline is regenerated for the evidence hashes. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…ence Completes the previous docs commit: the gitignore advice for openspec/ aborted the add chain, so the evidence attachment missed it. openspec/ ignores only new untracked files -- this change's artifacts are tracked, and the brief requires the sanitized legacy OKF import report attached to the change directory, so the evidence file is added with -f. The detect-secrets baseline is regenerated for the report's hex hashes, matching the established false-positive handling. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
pytest resolves rootdir (and its configfile) from the paths it is given, so any package-scoped invocation reads this package's pyproject.toml and never the workspace root's -m exclusions. Round 0 shipped the package config without them, so a plain 'pytest packages/agent-session-tools/...' silently ran the live_concepts suites: two 1 GB SQLite Online Backups of the owner's real sessions.db, a 140-second OKF import, and two committed evidence files rewritten -- the same trap fired during the independent review (B3 review round 1, Important #2). Add the -m exclusion for every opt-in marker this package declares (integration, live_ontology, live_concepts), matching the workspace-root convention and packages/studyloop's MUST-duplicate precedent, and pin it with a subprocess regression that proves package-scoped collection deselects every live-marked test by default while an explicit -m opt-in still selects them and ordinary tests stay selected. Co-Authored-By: Kiro <noreply@kiro.dev>
Round 0's committed migration receipt was captured at commit 1, before migrate_v49 gained its six replica_content_context_concept* triggers, so its whole-database schema_sha256 (5c2f2c56...) no longer described the shipped migration -- and nothing deterministic could catch that, because that hash covers every sqlite_master row and is therefore a property of the source corpus, not the migration (a fresh schema.sql install yields 81f3310a..., the real backup 6dfb4027...) (B3 review round 1, Important #1). Give the receipt a source-independent fingerprint instead: sidecar_migration_fingerprint() hashes the DDL of exactly the objects migrate_v49 installs (context_concept* objects, the two context_citations_bound_* guard triggers, the six replica_content_* triggers; FTS5 shadow tables excluded -- library-generated from the fingerprinted virtual-table declaration), emitted as sidecar_objects_sha256 (evidence_version 1 -> 2). Two always-on fixture regressions pin it: the name selection equals the complete non-shadow v49 delta (so a future migration edit cannot slip an object past the receipt check), and a fresh install of the shipped migration must reproduce the committed receipt's hash byte-for-byte. Receipt regenerated at HEAD on a fresh SQLite Online Backup (live DB untouched: v47, 5,813 sessions); its schema_sha256 is now 6dfb4027..., byte-identical to the review's independently reproduced value. Secrets baseline regenerated for the receipt's changed hex strings only. Co-Authored-By: Kiro <noreply@kiro.dev>
Bring the independently reviewed migration v49, lifted concept lifecycle/wind-down/import/projection, replication proofs, CLI/MCP surface, and full-corpus import evidence into the SessionWeaver Phase 2 integration branch.
Capture the existing public search contract before introducing the shared AND-to-OR planner. The fixture freezes row keys, deterministic ordering, null/default values, phrase/operator behavior, and the 300-character preview boundary.
Reuse the released SessionWeaver planner behind session_search while keeping its public row schema, SQL ranking, filters, and 300-character previews unchanged. Black-box tests prove the frozen cases remain identical and only the previously empty implicit-AND query widens through OR fallback.
Port SessionWeaver v0.2.0 concept-first recall onto StudyLoop's B3 authorization seam and shared query planner. The public MCP tool validates strict bounds, preserves the frozen report schema, deduplicates concept source sessions, and proves through behavioral traces that embeddings and ontology are not consulted.
Have studyloop install agents merge session-db and studyloop into Claude Code, Kiro, and Codex configuration without touching the real HOME. Format-preserving temp-HOME tests prove unrelated entries survive, repeated installation is byte-identical, missing configs are created, and doctor reports registration without mutation.
Repair an incorrect StudyLoop-owned JSON MCP entry by replacing only that value object, then append any missing owned entry. This avoids reserializing unrelated MCP entries while retaining byte-idempotence on subsequent installs.
Retain the exact 25-question corpus, aggregate-only v47 Online Backup evidence, and a reproducible released-reference acceptance runner. Document the frozen recall contract and MCP registration, add positive work/personal scope coverage, and mark OpenSpec B4 complete after a green 5,964-test preflight.
Route explicit phrase and boolean queries through the historical FTS escaping path so the shared recall planner remains frozen. Restrict AND-to-OR widening to empty implicit plain-text searches and pin compatibility with negative controls.
Replace owned JSON values and TOML subtrees by parser-validated byte spans rather than canonical-only regexes. This preserves unrelated configuration, prevents duplicate keys, handles CRLF and nested tables, and converges byte-identically on rerun.
Track TOML lexical state before recognizing candidate MCP table headers. This prevents owned-looking text inside multiline values from truncating unrelated config while retaining byte-preserving subtree repair.
…r programme Freezes, by this commit's hash, the gates that decide whether the concept sidecar, tier-1 ontology and embeddings are PROVEN to improve agent recall and decisions over the shipped FTS5 path -- before any of that code is touched on this branch. v1 was reviewed adversarially by a three-reviewer, two-family council (two REJECT, one APPROVE-WITH-CHANGES; 34 blocking findings, converging on the same weaknesses). v2 adopts the verified ones: cluster bootstrap with a +0.05 minimum lift instead of "CI excludes 0"; a DEV/SEALED gold split with one sealed look per gate; a content digest instead of an ids+counts fingerprint; a factorial B0/B1/B1+feature control; G1 scored on bound concepts only; a decision-correctness gate (G6); operational latency and payload budgets; G5 demoted to a blinded 40-pair pilot; and a claim matrix stating exactly what each gate does and does not license. Rejections and reasons are in the council receipt. The builder that must pass these gates did not set them alone, and cannot change them afterwards: changing this file is listed as never-automatic.
Gold v2: 216 candidates authored blind by three GPT agents from 150 sampled sessions (58% outside the PoC wind-down set), admitted by DeepSeek and Sonnet judges with a third-family adjudication where the first two applied the rules inconsistently. 175 admitted (57 K / 60 P / 58 R, balanced within 0.9%), 113 clusters, <= 2 per cluster; 41 rejected with reasons (26 answer_wrong). Split by cluster with a fixed seed: DEV 91 items committed here; SEALED 84 items stored outside the repository, read-only, SHA-256 recorded in the receipt and never passed to a builder agent. Harness (scripts/knowledge_proof/score.py): arms return ordered distinct session ids; recall@5 and MRR@5 per question; macro-average over strata; paired cluster bootstrap (10,000 draws) with established lift = lower bound >= +0.05; per-stratum non-inferiority; content corpus digest; hash-chained receipts. B0 is the shipped FTS path imported from a detached pin at 031dbab so later planner changes cannot move the control; B1 is the same path from the checkout. An arm that raises scores a miss and the error is recorded. Baseline on DEV: B0 = B1 = macro recall@5 0.107 (K 0.182, P 0.034, R 0.103). Finding F-B0-1: the in-flight _session_search_queries treats any question that contains the English word 'and', 'or' or 'not' as explicit FTS syntax and passes it to MATCH unescaped; 42/91 questions (46%) raise sqlite3.OperationalError and score as misses. main phrase-escapes every query and does not fail this way. To be fixed in Stage 3, where the B1-vs-B0 comparison quantifies the repair apart from any knowledge-layer lift. .secrets.baseline gains the receipts' SHA-256 fields via a whole-repo scan against the existing baseline; no other file's entries change.
…1 for the PoC overnight run The PoC is a new package with its own store, scored by the frozen ruler's gates on the existing blind gold set. Amendment 001 records, on Andy's instruction, the lifting of the programme-level caps (elapsed time, writer and council run counts) and the change of candidate; every measurement clause stays as frozen. The ruler file itself is untouched.
… dataflow Two showcase-validated archify specs authored from the ADR: the layered architecture (adapters → canonical events + evidence → derivation → learning content → consumers, live sessions.db read-only via the archive adapter) and the single-session dataflow (parse → events/evidence → exchanges → tags, recurrence, claims → claims-first recall). Independently re-validated by the orchestrator: 9/9 artifact checks, 0 composition errors, 0 warnings each. Delivered HTML (721 KB / 723 KB) is reproducible from the specs and stays ignored under the 500 KB hook. Browser visual-check could not run in the authoring sandbox; no perceptual review is claimed. The gitignore negation gains *.dataflow.json — the earlier rule covered only architecture specs, which would have silently left this one untracked.
…e invariants New package packages/learning-memory implementing ADR-0011's store: typed events with UNIQUE(session_id, content_hash); evidence written in the same transaction (OBSERVED native bytes or REPORTED prose for the archive); lineage; prose-only FTS5 (porter unicode61 default, unicode61 alternative, refused on mismatch); claims with a code-point bound-proof trigger on insert AND update, immutability, supersedes; claim_relations; review_items; exchanges/concept_tags/recurrence tables ready for the Stage D derivation pass. 67 tests, hypothesis-backed, exercise the invariants adversarially: re-ingest is a no-op over many passes; a session cannot exist without evidence; altered body, stale offsets, cross-session evidence, grapheme-splitting offsets, ambiguous repeats, empty and zero-width quotes are all rejected with no partial write; UPDATE on claims raises; tool text never reaches the prose index. Accepted deviations from the ADR text (now recorded in the ADR): deferred lineage for not-yet-ingested parents; position-free content hashes; native-byte body hashes; zero-width and rebind hardening; explicit dedupe instead of INSERT OR IGNORE, which had been swallowing CHECK violations. Verified independently by the orchestrator: 67 passed, ruff clean, pyright clean (after restoring the worktree env with `uv sync --all-packages` — the package-local sync had dropped studyloop from it), lane confined to the package plus uv.lock (root members glob already includes packages/*).
…al review Two seats (gpt-5.6-terra: REJECT/10 blocking; deepseek-3.2: APPROVE-WITH-CHANGES/7) reviewed v1.0 and the Stage B store with an identical brief, run separately. The orchestrator re-ran every probe the seats claimed and reproduced seven defects against the committed store, plus measured the corpus for the one whose severity depended on it (position-free dedup would drop 54.7% of user/assistant rows — 72,949 of them tool-echo markers, so `retried` could never fire). Changes written into the decision (not just the notes): - evidence is one row per prose event (citation surface = the event), append-only - a claim cannot exist without a citation — DB-enforced via deferred FK + trigger - position-bearing content_hash; adapters collapse adjacent exporter duplicates - lineage_pending reconciled when the parent lands (deferred edges were data loss) - prose_fts external content over a filtered VIEW so 'rebuild' stays prose-only - read contract: active / disputed claims; supersession same-session-or-lineage - search planner phrase-quotes every token; raw FTS syntax is a separate API - versions everywhere (adapter, classifier, derivation) + run manifest per receipt; SEALED look runs on a fresh work copy rebuilt from the manifest - derivation rules ship with a hand-labelled cross-harness fixture set Two Stage B notes withdrawn with the reproduction that killed them. All 42 findings and their dispositions (including four rejections with reasons) are in receipts/council-adr-0011.md. No ruler threshold or statistic changed. Stage B.1 (store hardening) is inserted before Stage C; its acceptance tests are the seven reproductions flipping to refused/correct.
…chema v2)
The seven defects the council reproduced against the Stage B store now flip
to refused/correct under the orchestrator's own probes, re-run verbatim:
D1 natural-language search goes through a phrase-token planner (raw FTS
syntax only via search_prose_raw); the DEV baseline's crashing query
returns hits. Property test found and fixed a NUL-byte truncation.
D2 evidence is append-only: UPDATE and DELETE refused by trigger.
D3 a claim cannot exist without a citation — refused at the API and at the
database (deferred FK, citations written first, AFTER INSERT trigger).
D4 prose_fts external content over a prose_events VIEW: 'rebuild' indexes
no tool text; 'integrity-check' passes.
D5 content_hash is position-bearing: every observed occurrence is a row,
re-ingest is still a no-op; adapters collapse adjacent exporter dupes
with collapse_adjacent_duplicates() and report the count.
D6 lineage_pending: a child ingested before its parent gets its edge when
the parent lands; circular pending pairs resolve; unresolved reported.
D7 evidence is one content-addressed row per distinct prose text per
session (event_id = first occurrence); OBSERVED captures retain raw
bytes; tool-only sessions still rejected even with native bytes.
Versions on sessions/ParsedSession/SourceRef; exchanges carry
derivation_version; concepts/concept_aliases/concept_occurrences replace
recurrence (tables only, no derivation). install() refuses an older schema
with SchemaError naming both versions.
132 tests (was 67); each new guard proven load-bearing by mutation (17/17
caught). ruff + pyright clean from the worktree root. Lane confined to the
package; uv.lock untouched. Deviations and the append-only redaction
consequence recorded in the ADR's Stage B.1 notes.
…sted read-only adapters/archive.py implements HarnessAdapter over the live sessions.db, opened ONLY as file:…?mode=ro (a test asserts a write through the adapter's connection raises). Session ids are unchanged (ADR §6). A pure, table-tested classifier maps every archive content shape to a typed kind; adjacent exporter duplicates are collapsed adapter-side and counted; lineage comes solely from metadata.source_session_id (485 agent-* edges, every parent present; 126 self-references skipped; 2,992 sub-agent sessions have no recoverable parent). Full ingest: 5,838/5,879 sessions, 106,362 events, 52,034 citable per-event evidence rows, 485 lineage edges, 15.9 s, 264 MB. Accounting closes with delta 0 (143,903 messages = events + 37,354 collapsed + 187 in rejected sessions). FTS holds exactly the 59,547 prose events and nothing else. The 41 rejections are all NoEvidenceError and all verified machine-only. Four facts in the orchestrator's brief were wrong and are corrected from data in the module docstring and the ADR: tool markers never carry arguments (retried on history = same tool NAME twice); messages.seq cannot order a transcript (id does); sessions.content_hash is NULL everywhere; kilocode/grok wrap learner voice in <task>/<user_query> — the first run rejected 167 sessions before that allowlist existed. The digest target the brief cited (a0df30bb…) is the WHOLE-gold digest and includes SEALED sessions; the DEV digest 9aa2b495… matches the baseline receipt exactly, computed by the imported pinned function. Orchestrator smoke on a scratch copy: the DEV baseline's crashing query returns a relevant top hit (360 ms cold, 31 ms warm, p95 40 ms); a real archive quote binds a claim; a fabricated quote is refused. 198 tests; ruff + pyright clean. .secrets.baseline: whole-repo scan adds the receipt's two digest fields.
…e the first DEV look The ruler requires the retrieval configuration on record before the number is seen. B1_clean = prose-only FTS (porter unicode61) over the archive-ingested learning-memory store, phrase-token planner, bm25 over 200 event rows, first 5 distinct session ids. No fusion, no claims, no embeddings — the arm that answers 'what does cleaning buy' and nothing else. Wire-tested on synthetic questions only.
…e shipped path First measurement of the programme, on gold DEV (91 questions, 60 clusters), chained to baseline-dev-031dbab9.json: B0 macro recall@5 0.107 (K .182 P .034 R .103) errors 42 B1 macro recall@5 0.107 (identical: no regression) errors 42 B1_clean macro recall@5 0.291 (K .424 P .172 R .276) errors 0 p95 41 ms B1_clean vs B1: Δ +0.184, paired cluster-bootstrap CI95 [+0.092, +0.281] -> lower bound ≥ +0.05: ESTABLISHED LIFT, every stratum up. Decomposition (so the number is not mistaken for crash-avoidance): on the 49 questions where the shipped arm did NOT throw, B1_clean scores 0.494 vs 0.320 (Δ +0.174; wins 11, loses 2, ties 36). On the 42 it threw on, 0.124 vs 0.000. Cleaning the indexed text is the effect; not crashing is additive. What B1_clean is: prose-only FTS over the archive-ingested store (tool echo and exporter duplicates excluded), phrase-token planner, same session ids. No derivation, no claims, no embeddings, no ontology. Declared in fusion-spec-v1.md at 690a37d, before this look. Gold sha 5632cd2b… = the DEV file's sha (matches the baseline receipt); the eeca2aaf… value in gold-v2-receipt.json is the item-set digest recorded at split time, a different quantity. Corpus digest 9aa2b495… = DEV, unchanged. G1 is NOT claimed: the gate requires macro ≥ 0.64 on SEALED; this is one DEV look (1 of ≤ 4 for the G1 family) at 0.291. The SEALED set was not touched.
…nance; declare B1_planner control The receipt council (gpt-5.6-terra, 4ed818c7) re-derived look 1's statistics exactly (CI95 [+0.0916, +0.2814], arm conformance exact, no leakage path) and returned VOID on provenance: the Stage 2 gold receipt's three hashes (dev.sha256, sealed.sha256, corpus_digest) do not reproduce from any surviving artefact. Verified: none of 384 serialisations of either gold file yields the recorded file hashes; the recorded corpus digest a0df30bb… reproduces from no item set (DEV∪SEALED, 175 admitted, 216 candidates, with/without cluster ids or the schema trailer). The hashes were computed by an in-session Stage 2 script that was not preserved. Under the ruler a gold/result digest mismatch voids the receipt and there is no evidence that could refute it. The gold DATA is intact on four independent checks: DEV byte-identical to its first commit; SEALED mtime equals the certification instant to the second and mode 0400; zero of the 114 gold sessions' messages postdate authoring; the DEV∪SEALED digest equals the admitted-bundle digest computed independently. ruler-amendment-002 records the dispositions (frozen ruler untouched). gold-v2-receipt-r2.json re-certifies with reproducible values produced by the committed recertify_gold.py (method in its docstring). score.py now records fusion-spec path/sha/declared-commit, store sha/size, and aggregate (macro) non-inferiority on every comparison; statistics unchanged. proof_arms gains B1_planner — the shipped index with only the planner swapped — declared in fusion-spec v1.1 BEFORE look 2 to apportion planner vs clean-index effect (council F6). visibility_sql excludes 0/5,879 sessions: scope is not a confound. Look 1 stays counted (1 of ≤4 DEV looks for G1); its receipt is marked VOIDED in place with numbers untouched. Look 2 must reproduce B0/B1/B1_clean exactly.
…ribution corrected
Same arms as look 1 plus the pre-declared B1_planner control (shipped index,
tool echo and duplicates intact, ONLY the query planner swapped), scored under
the corrected harness. Regression check: B0/B1/B1_clean per-question hits and
CI identical to look 1. Provenance now on the receipt: fusion-spec sha +
declared commit, store sha (252.6 MB), aggregate non-inferiority; gold sha and
DEV digest match gold-v2-receipt-r2.json.
B1 0.107 errors 42 p95 33 ms
B1_planner 0.249 errors 0 p95 66 ms vs B1 Δ+0.142 CI95 [+0.060,+0.231] ESTABLISHED
B1_clean 0.291 errors 0 p95 41 ms vs B1 Δ+0.184 CI95 [+0.092,+0.281] ESTABLISHED
B1_clean vs B1_planner (the clean-index increment):
Δ+0.042 CI95 [+0.009,+0.085] NOT established
(never loses: 4 wins, 0 losses, 87 ties)
Attribution, corrected from look 1's wording: the PLANNER is most of the lift.
Even on the 49 questions where the shipped arm did not throw, OR-of-phrases
beats the shipped AND-first form 0.479 vs 0.320 — the shipped query is too
strict, independent of crashing. A prose-only index adds a real but
sub-threshold +0.042 on top, and is the cheaper arm (p95 41 vs 66 ms; the
planner over the full index sits exactly at the 2×B1 latency line).
Look 2 of ≤4 for the G1 family. Improvement rule: the paired lower bound vs B1
is unchanged from look 1 (+0.092), so this look is NOT an improvement — one
more flat look stops the stage. G1 not claimed (needs ≥0.64 on SEALED).
… record for looks 1–2 Second-family seat (deepseek-3.2, 74685923) on look 2: VALID-WITH-NOTES, one blocking finding — look 2's previous_receipt_sha256 hashed the look 1 file AFTER it had been edited in place to add a VOIDED field, not as committed. The orchestrator's error. Remedy: look 1 restored to its committed bytes (sha ec9d6576…, identical to ca55c65), the void notice moved to a sidecar (stage-d-look1-b1clean.VOIDED.md), look 2 re-run chained to the pristine file. All four arms reproduce identically; chain verified against `git show ca55c65:…`. Rule adopted: a receipt is never mutated after commit. B1_planner now carries the shipped visibility predicate so "identical to B1 except the planner" is literally true (predicate excludes 0/5,879 sessions; per-question hits unchanged). council-stage-d-looks.md records both seats' findings with dispositions and evidence. Standing: look 1 voided (numbers reproduced), look 2 valid; planner +0.142 established, clean +0.184 established, clean-over-planner +0.042 not established; stop rule 2 armed (one more flat look ends the G1 DEV looks). G1 not claimed. SEALED untouched. Council runs 13.
…led, accuracy measured derive.py (DERIVATION_VERSION derive-v1): exchanges threaded per user turn with quarantine for pre-first-user blocks; is_question / had_error / retried / resolved per the ADR rules; concepts from the shipped extractors/topic_vocab.json (7 areas, 103 terms; copied into the package, sha-pinned) with alias forms; concept_occurrences; recurrence candidates computed for the receipt; intent and outcome written onto sessions. Idempotent per (session, version) — proven on the real corpus by byte-identical content hashes across two runs. Whole store: 5,838 sessions in 19.3 s; 15,995 exchanges (11,860 threaded = the user-event count, 4,135 quarantined); 109 concepts, 35,136 tags; intent 91.9 %, outcome 37.6 %. Corpus fact: 32.4 % of consecutive learner turns are byte-identical re-asks — the builder suspected a difflib artefact, measured it (a length guard reclaims 6 of 2,211), and kept the rule. The 60-exchange fixture was labelled BY THE ORCHESTRATOR by hand (the ADR forbids a model writing its own answer key). Measured agreement with derive-v1: is_question 42/60 (fires on imperative briefs), had_error 51/60 (misses errors the LEARNER pasted — lexicon scanned answers only), retried 48/60 (name-only on the archive = ordinary repeated tool use), resolved 48/60. Concept recall ≥ 0.90. The label tests are reshaped from "zero disagreements" into measured floors (fail on regression) with an xfail'd 90 % target; the fixes the labels justify are a derive-v2 with a re-label pass, recorded in the ADR. Also fixes a Stage B store defect a hypothesis draw exposed this run: the citation resolver's ambiguity MESSAGE used str.count (non-overlapping) so body '???' / quote '??' was refused with "occurs 1 times"; the decision was already correct. count_overlapping() now backs both the message and the property test's precondition; regression test added. 299 tests, 4 xfail.
… a derived artefact Before any model writes a claim: claims-writer-spec-v1.md fixes the model (claude-sonnet-5), the prompt (writer_prompt_v1.md, sha on every claim and receipt), the strict output schema, the insertion contract (≥1 overlap-aware unambiguous quote per claim, cross-session citations refused, no partial inserts, post-run substr() re-check proving unbound writes = 0), budgets (pilot 40, population ≤302, hard cap 400), and the G2 audit: blinded (statement, quote)-only entailment by a second family on 100 random claims, seed fixed, with a fixed failure taxonomy. What v1 deliberately omits is listed. The ruler binds G2 to "the 348 PoC sessions" with no committed list. Found its definition (RESULTS-final.md: updated ≥ 2026-08-01, ≥10 messages) and the run's own frozen corpus snapshot, whose sha matches the run's SHA256SUMS. pin_poc_set.py reproduces the rule against that snapshot: 345 (the snapshot was cleaned of empty rows AFTER the 348 was counted; 3 fell below threshold). All 345 exist today; 342 are in the store. Under typed events "≥10 messages" means prose events: 200 sessions. ruler-amendment-003 records both denominators and declares n_prose_ge10 = 200 primary for the G2 clause, without editing the ruler. Population is hash-ordered by session id. 26 of 60 DEV gold sessions lie inside the 342 by design of the gold split (verified, not assumed); the writer is gold-blind by construction (no gold file readable from its environment, asserted by test), not by instruction.
…, substr re-check, receipts scripts/knowledge_proof/claims_writer.py: the deterministic half of the writer. It calls no model. population (342 ingested PoC sessions, hash-ordered, prose≥10 subset 200), packet (per-event citable evidence + derive-v1 flags, ≤48 KiB with truncation recorded, prompt and packet sha256), render (byte-deterministic prompt text), ingest (strict JSON; every schema and citation refusal recorded with reason; never a partial insert; post-run SQLite substr() re-check of every inserted citation; a writer label whose prompt sha does not match the packet's fails the run), summarise (yield on both G2 denominators, refusals by reason, recheck total, runs used). Gold-blind by construction: the module contains no gold or sealed reference (test-asserted); packets are built from the store alone. Orchestrator smoke on a scratch copy: a fenced response with one grounded claim, one fabricated quote and one citation-less claim → inserted 1, refused 2 (citation_unbound, no_citations), recheck_mismatches 0. The real store still holds zero claims. 52 harness tests; ruff + pyright clean. pyproject testpaths gains scripts/knowledge_proof/tests (the one permitted line outside the lane). Note: the builder saw 16 failures in packages/studyloop/tests locally; CI is green on every pushed commit, and the one reproduced (test_cli_brain expecting exit 1) assumes no second brain is configured — a pre-existing test-isolation issue on main, out of scope.
…d and entailment below gate Pilot: 40 sessions in hash order, 40 claude-sonnet-5 writer runs, packet-only context. 183 claims proposed, 162 inserted (104 Finding, 25 Decision, 19 Procedure, 12 Problem, 2 Preference), 180 citations, UNBOUND WRITES 0 by SQLite substr() re-check of every citation. 21 refusals: 13 paraphrases, 8 from one session where the writer cited row numbers instead of evidence ids on a 141-row packet — the harness held on every one. Yield on the pre-registered primary denominator: 24/29 = 82.8% (gate 90%). Decomposed, not argued: 4 of the 5 misses are sessions inside the denominator with no learner voice (no learner turn; council-judge briefs; a pasted AGENTS.md); 1 is the id-format defect. On sessions with learner voice: 12/13. Blinded entailment audit (deepseek-3.2, 100 claims, statement+quotes only, key outside the repo): 82 yes / 18 partial / 0 no (gate 95%). Taxonomy: hallucinated-detail 13, over-claim 4, preference-inferred 1. Decomposed: for 14 of the 18 partials the statement's extra details ARE in the session's evidence — the writer read them and cited only one sentence (86/100 claims carry a single citation). 4/100 contain material absent from the session. Transcript fidelity ~96%; citation completeness 82%. G2 is defined on completeness, correctly. G2 NOT PASSED on the pilot. Per the ruler: investigate the writer, never relax the trigger. Next: writer-v2 spec (every factual element covered by a quote; prefer 2+ citations; cite by 64-hex evidence_id only) and a fresh blinded audit. The no-learner-voice denominator finding is recorded for the ruler owner, not changed here. Harness: cap now truncates to 8 and records dropped_over_cap (spec deviation, documented on the receipt).
… before any v2 run Each prompt change is tied to a measured failure from the pilot audit: element-by-element quote coverage (14 under-citation partials), prefer 2–3 citations (86 % single-citation), verbatim 64-hex evidence_id (the 8-claim row-number refusal), statement ≤ 300 chars, no stating implication as fact. Held fixed: model, the same 40 sessions and byte-identical packets, harness, insertion contract, auditor family and blinding; fresh audit seed over v2 claims only. Pass/improve/stop readings declared in advance; two prompt rounds without passing stops Stage E.
…oid the reading, pin the brief The v2 blinded audit returned 17/100 yes, but the brief had been rewritten from memory (stricter wording) and the auditor ruled 3 of 4 known-answer items wrong (statements verbatim from their quotes marked 'partial'). The reading is void as a gate measurement, kept as the record of the fault. The v1 brief is extracted verbatim into a committed template so every future audit is byte-reproducible; the remedy (re-audit both samples with the pinned brief, measure auditor noise on the already-scored v1 sample) is declared before it runs.
…ms: 82 → 16 yes Noise control on the already-scored v1 sample: per-item agreement 34/100, all 66 flips yes→partial. No single-seat entailment reading (v1's 82 included) is a valid G2 measurement. Protocol declared before running: majority-of-three within family plus a gpt-5.6 cross-family seat on both samples, gate reading = the lower of the two, and an explicit 'not measurable' outcome if the families disagree by >10 points.
…; G2 not established: instrument Writer-v2 on the same 40 sessions and byte-identical packets: 145 claims, 0 unbound writes, citations/claim 1.11→1.55, single-citation 89%→54%, the row-number defect gone, yield 23/29 (v1 24/29) — five agent-brief sessions now yield nothing, two warm-ups gained one claim. Audit under the pinned brief, seven seats total. deepseek on the identical v1 items: 82 → 16 → 86 yes (per-item agreement 34/100 between the first two; unanimous across three on 27/100). gpt-5.6: v1 58, v2 77. deepseek valid seats on v2: 91, 96. Every clean seat ranks v2 above v1 (deepseek +12, gpt +19). Families disagree by 21 (v1) and 14 (v2) points — over the pre-declared 10-point bound — so G2 is recorded NOT ESTABLISHED — INSTRUMENT rather than passed or failed on a number nobody can reproduce. Two findings for the ruler owner, recorded not actioned: the audit clause needs a reliability floor before it can be met or failed; the primary yield denominator contains sessions with no learner turn.
…before the last DEV look Pilot claims cover 3 of 60 DEV gold sessions (6 of 91 questions, no paraphrase items); a claims arm over them would be flat by construction and would fire the stop rule for a reason unrelated to the architecture. The full population reaches 26 gold sessions / 39 questions across all strata, inside the ruler's 400-run writer budget (382). Ruler unchanged; spec-v2 deviation stated.
…ms declared before look 3 Two arms, declared with their coverage bound (19/60 DEV gold sessions carry a writer-v2 claim; a claims-only arm can reach 30/91 questions) before any look-3 run. recall_claims: in-memory FTS5 over writer-v2 claims (title, statement, tags), same planner as B1_clean, bm25 then claim rowid, first K distinct sessions. B1_clean_plus_claims: reciprocal rank fusion (k=60, 1-based ranks, weight 1) of the two full deduped rankings, tie-break best prose rank then session id. B1_clean's ranking is factored into a shared helper so the fused arm consumes the same list B1_clean cuts; its output is unchanged (tested). score.py now emits comparisons between every ordered pair of feature arms, so the attribution reading B1_clean_plus_claims_vs_B1_clean is produced by the committed script. Statistics unchanged. 63 harness tests pass.
…bound writes, 19/60 DEV gold sessions covered 302 sessions attempted in gold-blind hash order; 301 responded; one (index 318, not a gold session) was refused at the agent layer on both the first run and the single permitted retry and is recorded as not attempted. Yield on the primary denominator 149/200; refusals are paraphrases the harness held. Writer runs 384/400. Coverage bound for look 3 recorded here and in fusion-spec-v2 before the look.
…_clean); G1 looks end B1_clean_plus_claims 0.151 vs B1_clean 0.291, Δ −0.140 CI95 [−0.245, −0.041]: not established and significantly worse. Two flat looks → the two-flat-looks stop rule fires; no look 4. B1_clean +0.184 over B1 reproduced exactly. recall_claims alone: 0.130 (R 0.207 > B1 0.103; P 0.000) within its 30/91 coverage bound. Mechanism from the receipt: fused lost 17 questions B1_clean had (gold at prose rank 1–2 in 12/17, absent from the claims list in 16/17, fused rank 7–39) and gained 4. Equal-weight RRF over a ~127-session OR-planner claims list promotes any weakly matching claimed session above the best prose hit. ADR-0011's retrieval benefit is NOT ESTABLISHED on DEV under G1; recorded, not re-tried.
…h, established; G1 bar not met SEALED (84 questions, 56 clusters, sha 90ef67ad byte-verified, mode 0400 before and after, fresh store copy deleted after use): B1_clean 0.283 vs B1 0.115, Δ +0.168 CI95 [+0.076, +0.268], non-inferior on K/P/R — the DEV result (+0.184) replicates on held-out data. Claims fusion replicates its harm (−0.154 vs B1_clean, CI95 [−0.252, −0.065]). G1 NOT ESTABLISHED: the clause's 0.64 macro bar for a fused arm is not approached by any arm built here. The composite claim may not be written. The shippable finding stands: the shipped AND-first planner is the defect; a phrase-token OR planner over prose-only FTS is a +0.17 recall fix.
…CHANGES; dispositions recorded The gpt seat's BLOCKER (receipts void on digest mismatch) is refuted on the artefacts: every result receipt's digest equals amendment-002's committed per-split reference (DEV 9aa2b495 at looks 2 and 3, SEALED 965f5b1e); the field the seat compared against carries the superseded, non-reproducible original digest — a record-keeping defect, accepted. Also accepted: the digest omits retrieval configuration (provenance gap); the stop-rule wording is restated in the ruler's lower-bound terms (+0.092 → +0.092/+0.060 → −0.054: two looks without a rise); the mechanism evidence is now retained by a committed script (look3_mechanism.py → stage-f-look3-mechanism.json: lost 17, gained 4, gold at prose rank ≤2 in 12/17, absent from claims list in 16/17); and B1_clean's lift is relabelled a prose-control planner finding, not a G1 or knowledge-layer result. Gate outcomes unchanged.
… finding; deviations; follow-ons Status → measured, not established (v1.2). G1: fused arm 0.129 on SEALED against a 0.64 bar, worse than the prose control (−0.154). G2: binding held (0 unbound over 2,057 citations); entailment not measurable with a single-model blinded audit. Composite claim not writable. Established separately: the pre-declared prose control beats the shipped path by +0.168 on SEALED — a planner fix for agent-session-tools. Three deviations from the ADR/ruler text recorded with their mitigations.
… showcase) Minimal truthful revision of the Stage A architecture diagram: the retrieval path that was established on SEALED (prose_fts, OR planner, +0.168) is the emphasised edge; the claims fusion edge carries its measured −0.154; the three cards state what is established, what is not, and what held. archify validate --quality showcase: ok; deliver: ok (specification sha a65b0878…, artifact sha 5a79003e…). visual-check could not run in this environment (Chrome sandbox init refused; the Stage A artefact fails identically here), so browser evidence is not claimed.
…ary gap, 35% ranking Deterministic, read-only census over every learner turn in the 2,361 human-driven sessions (8,414 turns; 1,144 pastes over 200 words and 2,693 sub-3-token turns excluded; 4,577 measured). Two proxies per question: stemmed content-token overlap with the REST of its own session, and whether the committed prose FTS + OR planner recovers the question's own session in the top 5 from the other turns alone. Median overlap 0.67; only 7.4% of questions share no content word with their transcript. Self-retrieval: hit 57.3%, miss-by-vocabulary-gap 7.4%, miss-by- RANKING 35.3%. Ranking failures outnumber vocabulary failures five to one, and the vocabulary figure is inflated by unanswered sessions and two adapter artefacts (kilocode 48%, gemini 22% vs kiro 8%, codex 1%, claude_code 0%). Own-session comparison is a lower bound on cross-session drift; stated in the artefact. Decision input for the embeddings question, not a gate.
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.
Stacked on #18 (
feat/sessionweaver-phase2-retrofit); do not merge before it.Purpose of this PR is the pre-registered proof programme for the concept sidecar, tier-1 ontology and embeddings. It exists as a draft so GitHub CI runs on every push — the authoring sandbox cannot run Chrome or
ps, so CI is the zero-failure oracle named in the ruler.docs/architecture/session-memory/validation-ruler.mddocs/architecture/session-memory/receipts/council-ruler-review.mddocs/architecture/session-memory/receipts/as stages complete.Merge decision stays human. Changing the ruler is listed as never-automatic.