Files
GEWU/docs/acceptance/2026-10-13-foundation.md
2026-10-14 19:21:35 +08:00

239 lines
51 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Foundation implementation evidence
Date: 13 October 2026
Scope: local development host, Python 3.14.7, Node 26.8.1, Linux.
Status: component checks PASS; disposable source-to-citation flow NOT RUN.
## Backend
Commands: `make check`, `make typecheck`, `./scripts/python-tool mypy src tests`, `make test`, `make schemas`, `make boundaries`, and `git diff --check`.
Observed: Ruff passed; mypy passed for application and test modules; 33 pytest tests passed; schemas and catalog regenerated; import boundaries passed; whitespace check passed. Tests cover strict contracts, fixture catalog, exact claim and edge evidence, upload resume/hash/path constraints, text extraction maps, Git expected-head publication, acceptance receipts, idempotent retries and recovery after publication-before-receipt crashes.
## Frontend and dependencies
Commands: `npm run check`, `npm run build`, and `npm audit --audit-level=moderate` from `web/`.
Observed: TypeScript, ESLint and Vitest passed (1 test); Vite production build passed; npm audit reported zero vulnerabilities.
## Limits
These checks run only on the stated local runtime. Python 3.12, other operating systems, native client discovery and workflows, MCP, retrieval, browser citations, real-source quality, deployment and restore remain NOT RUN. Synthetic fixtures do not satisfy the PRD's 20-source pilot evaluation. No pilot or release gate is claimed complete.
## Authenticated canonical read continuation
Additional commands: same backend command set plus `make check`, `make typecheck`, and `./scripts/python-tool mypy src tests`; frontend commands were rerun.
Observed: 40 backend tests passed. Added SQLite credential hash/revocation/rotation coverage and an HTTP test that confirms missing credentials get 401, malformed IDs get 422, a cross-project read gets 403, a granted read returns the committed revision and citations, and revoked credentials get 401. Local factory and SQLite identity setup reject symlinked data paths. Frontend checks/build passed; npm audit reported zero vulnerabilities. Local `make dev` now composes the Git repository and credential store under private `GEWU_DATA_ROOT` (default `.data/gewu`); `make provision-credential ARGS="..."` provisions an operator-created credential and displays it once. After the 40-test suite, the focused API/identity group was rerun and passed (8 tests); Ruff, mypy and `git diff --check` passed again.
This is one-node canonical reading, not search or the M3 browser flow. There is no human bootstrap/reset or browser session mechanism; an operator must control the local provisioning command and data root. Proposal submission and durable acceptance do not yet use the SQLite identity store.
## Authenticated MCP read continuation
The official Python MCP SDK v2.3.0 is locked as the Streamable HTTP transport. A protocol-level test connects an SDK client through the mounted MCP endpoint, lists the single `get_node` tool and reads the committed node/citations. Missing and revoked credentials return tool errors without node data. Host validation is restricted to loopback names in the local composition; public deployment host policy is not configured. The SDK's current v2 API and stdio/Streamable HTTP split are documented by the [official SDK](https://py.sdk.modelcontextprotocol.io/) and [server transport guide](https://py.sdk.modelcontextprotocol.io/run/).
The pilot fixture now has a single unambiguous shared test policy and validates JSON duplicate-key rejection.
## Authenticated contribution and source-to-citation continuation
Commands: `make check`, `./scripts/python-tool mypy src tests`, `./scripts/python-tool pytest -q`, `npm --prefix web run check`, `npm --prefix web run build`, and `npm --prefix web audit --omit=dev`.
Observed on the same local Linux/Python 3.14/Node 26 environment: 46 backend tests pass; Ruff and mypy pass; frontend TypeScript, ESLint and Vitest pass; production build succeeds; npm audit reports zero vulnerabilities. `tests/api/test_mcp_contribution.py` uses the MCP SDK client and an isolated temporary repository to upload a Markdown fixture, deny a cross-project upload, verify its hash, extract a location-mapped block, submit an attributed proposal under the test policies, confirm automatic acceptance and read the committed node with the exact citation. `tests/application/test_registry.py` seeds and parses the explicitly disposable registry. Identity revocation and publication now share the canonical-writer lock in the local composition. Catalog regenerated with all exposed contribution tool names.
This is synthetic local evidence, not a pilot result. The artifact-store contract test now uploads identical bytes for two project grants, verifies one content-addressed artifact is readable under both grants, and verifies an ungranted project is denied. Exact retry/restart across the complete source-to-acceptance flow, native host discovery, browser citation reading, retrieval/index behavior, real policy/ownership, real-source quality, other runtimes/OSes, deployment and restore remain NOT RUN. The initial UI was health-only at this point; the authenticated reader is documented later. A later MCP contribution test verifies that a quote found at the wrong locator is rejected with `EVIDENCE_MISMATCH` before a valid proposal is auto-accepted, and that exact accepted-proposal retry returns the original receipt without another commit. The disposable local-slice gate remains open until its remaining criteria pass.
## Explicit-file stdio connector continuation
The `gewu-connector` entry point exposes only `list_selected_files` and `upload_selected_file` to its local MCP peer. File IDs and paths are supplied by the operator at process launch. It rejects symlinked or non-regular files, caps bytes at the service limit, requires HTTPS for non-loopback service URLs, reads the bearer token from `GEWU_TOKEN`, and returns only file metadata, content hash and extraction IDs. A private mode-0600 state file checkpoints upload IDs and finalized artifact hashes; retries query server-verified offsets and resume without resending completed chunks, including after a connector restart.
The connector contract test simulates a restart by creating a fresh local MCP server instance against an in-process mock service. It interrupts transfer after the first chunk, interrupts again after finalization, then resumes extraction from the saved artifact. The end-to-end contribution test also invokes the connector over a real MCP Streamable HTTP session to the local GEWU ASGI service. Together they verify byte/hash equality, no source bytes or absolute paths in local tool results, rejection of an unallowlisted file ID, and rejection of a symlinked selected path. This does not prove an OS process restart/kill, public remote deployment, TLS certificate/service identity under a native host, actual client configuration, or Windows/macOS file semantics.
Updated validation: `make check`, `make boundaries`, `./scripts/python-tool mypy src tests`, `./scripts/python-tool pytest -q`, frontend check/build, `npm audit --omit=dev`, and `git diff --check` pass; the backend suite now has 60 tests. Python dependency `httpx2` is declared directly because the connector configures bearer headers on the MCP Streamable HTTP client; its v2 transport contract is documented by the [official MCP SDK client transport guide](https://py.sdk.modelcontextprotocol.io/client/transports/) and [HTTPX2 project page](https://pypi.org/project/httpx2/).
## Preliminary scoped lexical search
SQLite 3.53.4 in this Python 3.14.7 Linux runtime provides FTS5. `SQLiteSearchIndex` uses a disposable FTS5 table plus a project-indexed canonical-record table, WAL journaling and `synchronous=NORMAL`; every connection closes explicitly. Query terms are quoted and bound as a parameter, project IDs use generated placeholders, and only registered/authorized project IDs reach the query. The service reads just the small project registry for scope validation. A missing index rebuilds transactionally from a pinned Git revision; a revision change triggers a rebuild. A source/commit race returns the older index revision with an `INDEX_LAG` warning.
The tests cover HTTP/MCP search, missing/cross-project scope denial, complete citations, stale-node warnings, exact revision disclosure, budget omissions and too-small errors, FTS rebuild on a new Git revision, fresh-index reconstruction, and an injected canonical-advance/index-lag case. `EXPLAIN QUERY PLAN` on the scoped FTS query reported `SCAN node_fts VIRTUAL TABLE INDEX 0:M6`, followed by a `SEARCH indexed_nodes USING INDEX indexed_nodes_project (project_id=? AND node_id=?)`; ranking uses a temporary B-tree. This is query-shape evidence only. No 10,000-node latency or 100,000-node rebuild benchmark has run.
The current budget unit is explicitly `unicode-codepoints-v1` over the complete canonical JSON envelope. It preserves each result with its complete citations and retains warnings while dropping lower-ranked groups. This is an interim, deterministic contract and does not represent model tokens; the tokenizer/encoding decision and offline tokenizer assets remain open. Authenticated HTTP/MCP neighbor reads return typed edges with endpoint nodes, filter node endpoints by the explicit project/shared scope, preserve edge and neighbor citations, apply freshness and index-lag warnings, and use the same complete-envelope budget. Source metadata is included only when its `ingested_for` grant intersects the authorized scope. Edges, source metadata, source-grant rows and nodes are indexed in the same transactional SQLite rebuild; schema version 4 forces existing derived indexes to rebuild. Adapter tests verify source grant filtering, while HTTP/MCP tests verify project isolation, citations and transport availability. Authenticated HTTP/MCP list_projects discovery filters registry IDs against the caller's grants. Lexical search cursors bind the query, resolved project scope, shared flag, page size and SQLite index revision; invalid cross-query cursors return 422, changed-index cursors return 409, and cursors advance only past results included under the response budget. A caller can retry a budget-truncated page with a larger budget. Neighbor pagination filters inaccessible endpoints before offset/limit, binds cursors to the same index revision, returns distinct pages through HTTP, and expires old snapshots with 409. HTTP/MCP source metadata and bounded node-history reads are now tested. Source reads return 404 when the source revision is not ingested for the requested authorized project, and history returns validated versions from the canonical Git path. Archived artifact download is now available through the authenticated project source route; browser integration for exact extraction location preview, synthesis dependency warnings, CJK/language qualification, hybrid ranking and performance gates remain NOT RUN. Search/M1.4 and the broader M1 milestone remain partial.
## Authenticated reader continuation
The React reader now uses the read-only HTTP API for project discovery, scoped search, canonical note reads, source metadata and node history. It presents exact quotation text and locator details, freshness and index-lag notices, loading/empty/error states, and query/project state in the URL. The bearer credential is held in component memory, never persisted to browser storage, and the disconnect control clears the reader state. No capture, edit, approval, merge or generation action is exposed. Vite proxies `/v1` to the local API for same-origin development requests. Tests cover the connect → search → note → citation → source metadata flow and verify that localStorage remains empty; frontend type/lint/unit checks and production build pass.
The sign-in form exchanges a human viewer credential for the planned browser session; the bearer secret is dropped after exchange. Archived source bytes are now downloadable to authorized readers; the browser does not yet provide exact location preview. The T3 collaborative preview DOM measurements at 1440×900, 1024×768 and 390×844 showed no horizontal overflow; a 320×844 resize timed out. Snapshot capture repeatedly failed. Screenshots, 320 px reflow, 200% zoom, keyboard-only end-to-end review, screen-reader review and axe results remain NOT RUN. The M3 browser and visual acceptance gates remain partial.
## URL-owned search facets (2026-10-14)
Search now accepts exact tag, audience, use and domain filters through authenticated HTTP and MCP. SQLite applies each selected facet group before pagination; values within one group are ORed, while distinct groups are ANDed. Continuation cursors bind all selected facet values, so changing a filter cannot reuse an old page token. The browser initializes these filters from the URL, writes changes back to it, and clears the active cursor when a filter changes. Facet choices are informed by loaded results, while text entry permits an exact value outside those suggestions.
Tests cover matching and non-matching HTTP filters, cursor rejection after a filter changes, MCP facet forwarding, and multiple values within a facet group. Search also accepts an empty query only with a knowledge-type filter; HTTP returns 422 for an empty untyped request. SQLite tests verify problem-only results, project isolation, and stable non-overlapping cursor pages. HTTP and MCP tests verify problem browse returns the authorized fixture. The frontend test exercises “Browse problems” and confirms that it sends an empty query with `node_types: ["problem"]` and records the type in the URL. On the local Linux/Python 3.14.7/Node 26.8.1 environment, schema/catalog/MCP-contract generation and pack-manifest verification pass; Ruff, mypy (33 source files), boundary checks, all 111 backend tests, TypeScript, ESLint, all 11 frontend tests, production build and both whitespace checks pass. At 320×800, T3 DOM measurement of the disconnected screen reports document width equal to the viewport; the navigation strip scrolls horizontally. Authenticated interaction and visual snapshots remain unverified because preview snapshots fail and the available preview is disconnected. Screenshots, 200% zoom, keyboard-only and screen-reader review, and automated accessibility results remain NOT RUN. M3.3 remains partial pending cross-project explanations and the outstanding visual/accessibility protocol.
## Selected-node URL restoration (2026-10-14)
Opening a search result or related suggestion now adds `node` and `node_project` to the current scoped search URL. The node project is explicit because a visible shared record may differ from the active search project. After authentication, a direct node link performs the canonical read through the authorized project route and restores citations, history and relationships. Back navigation removes the selection and clears its private reader data; forward navigation restores it from the still-loaded result page or an authorized canonical read. Changing search or project clears the old node parameters. The route does not expose credentials or private response data.
Frontend tests cover a direct shared-node URL after connection and back/forward movement across an opened node. T3 preview could not exercise the authenticated flow: snapshots fail and the available tab remains on the disconnected screen. The production API now accepts an optional Git commit ID for node reads, confirms it appears in that node's latest 20 reachable revisions, and returns that exact node with citations. Invalid revisions receive 422; commits absent from the node history receive 404. MCP `get_node` accepts the same optional revision. The reader makes history entries selectable and stores an explicitly selected node-file commit in `revision`; it uses the latest commit that changed the node rather than the repository HEAD, which may have advanced for unrelated records. The default node URL continues to read current accepted state. Revision-pinned views omit current-index relationships and explain why. Shared URLs and browser history restore the selected revision. API tests cover the latest node-file commit differing from repository HEAD, historical content/citations, and invalid or unknown commit IDs; UI tests cover direct historical links, selection and revision back/forward. On local Linux/Python 3.14.7/Node 26.8.1, the final checks pass: 111 backend tests, 11 frontend tests, Ruff, mypy (33 source files), import boundaries, generated schemas/catalog/MCP contract, pack manifest verification, production build and root/submodule whitespace checks. T3 authenticated behavior remains unverified.
## Shared search URL restoration (2026-10-14)
After browser authentication, a direct URL containing a query and exact filters now runs that scoped search and restores its results. Browser back/forward to a different query/filter route follows the same path. Query and facet edits continue updating the shareable URL without issuing requests until the user presses Search; the first draft edit creates a history entry, later edits replace it, and submit commits without a duplicate entry. Tests verify a shared query/tag/audience URL issues one scoped request, typing remains passive, and one Back/Forward step restores and reruns the corresponding prior/next search. TypeScript, ESLint and all 13 frontend tests pass; production build and the previously recorded backend/schema/pack gates pass. Authenticated T3 preview, two-minute reading task, and visual/accessibility evidence remain open.
## Synthetic search capacity baseline (2026-10-14)
Added `make benchmark-search` for repeatable synthetic measurements through the production SQLite search adapter. On an Intel Core i7-7700HQ laptop, Linux 7.2.5, Python 3.14.7 and SQLite 3.53.4, a 10,000-node single-project corpus produced 20 scoped results; 30 warm searches measured p50 23.8 ms and nearest-rank p95 26.7 ms. Cold index rebuild plus first search was 43.6 seconds. A 100,000-node corpus split across ten projects (10,000 each) measured 10 warm searches scoped to one project at p50 132.5 ms and p95 144.4 ms; cold rebuild plus first search was 422.3 seconds. Both observed warm adapter runs are below 300 ms, and the synthetic 100k rebuild is below ten minutes.
These are partial R3 evidence, not a release pass: the benchmark feeds an in-memory canonical repository, excludes Git I/O and HTTP/auth overhead, repeats one valid claim shape, and does not test semantic retrieval quality or concurrency. The PRD workload, cache assumptions and target machine remain unfixed. Detailed reports: [10k project](search-benchmark-10000.json) and [100k total](search-benchmark-100000.json). `make check`, `make typecheck`, `make test` (111), `make boundaries`, frontend check (13), production build, and root/submodule whitespace checks pass with the benchmark script in the worktree.
## OS-level publication recovery (2026-10-14)
Added subprocess tests that call `os._exit` immediately after the canonical Git ref update and before durable receipt creation. The parent process then constructs fresh repository and acceptance-service instances, runs recovery, verifies the receipt points to the already-committed revision, checks author-scoped accepted status, and retries the proposal without advancing Git HEAD. It also starts with an empty derived index, rebuilds from that recovered canonical commit, and confirms the accepted citation is searchable. At this stage, abrupt index-rebuild termination and unrelated queued work were still open; the following evidence closes those local checks.
## Canonical repository replacement contract (2026-10-14)
Moved repository conflict and failure errors to the application-owned port and centralized its portable relative-path validation. The shared contract now runs against both the production Git adapter and an independent in-memory adapter: expected-head publication, immutable prior-revision reads, scoped file listings, introducing commit/history order, missing paths and rejection of stale writes and traversal paths. The existing `CanonicalNodeReader` is also exercised unchanged against the in-memory adapter and returns the same canonical node, revision and citation. Acceptance orchestration now catches only port-owned errors and has no Git adapter import. Ruff, mypy, import boundaries, and the full backend/frontend pipelines pass. The substitute proves dependency isolation and the contract cases listed here; it does not prove another backend's locking, durability, crash behavior or production equivalence.
## Recovery gate for unrelated work (2026-10-14)
With a proposal journal left pending after ref update, the test corrupts its expected manifest digest to force reconciliation to fail. An unrelated proposal submitted during that failure receives `RECOVERY_REQUIRED`; its proposal file is not written and canonical HEAD remains unchanged. After restoring the verified digest, explicit recovery reconstructs the first receipt, and retrying the unrelated proposal publishes successfully. This covers one unrelated queued proposal across the recovery gate; it does not claim queue-load capacity.
The index rebuild crash test now starts from an already complete eight-node generation, publishes four additional canonical nodes, and terminates a subprocess after five FTS inserts in the new generation's transaction. SQLite retains the old eight-node rows and revision with no partial writes. A subsequent ordinary search rebuilds the current 12-node generation and returns all nodes. Together with the publication and adapter-contract cases above, this satisfies the listed local M0.6 and M0.7 acceptance checks; broader PRD corpus, platform, pilot and release gates remain separate.
## Human browser session continuation
Human admin/editor/viewer credentials can exchange for an eight-hour server-side session represented by an HttpOnly, SameSite=Strict cookie. The server stores only session and CSRF digests; cookie-authenticated POST reads and sign-out require the matching CSRF header. Session creation enforces same-origin when an Origin header is present. Agent credentials are denied session creation. Browser-session principals carry a distinct auth method and cannot submit agent proposals; revoking the underlying credential makes the session unusable. The UI clears the typed bearer credential after exchange, keeps the CSRF token only in memory and signs out by revoking the server session.
Tests cover human/agent session eligibility, cookie flags, same-origin rejection, CSRF rejection and success, sign-out, session invalidation after credential revocation, and prevention of proposal submission through a browser-admin principal. This completes only the browser-session portion of M1.1. Restricted first-admin bootstrap, owner grants and the separate digest-bound protected owner authorization/challenge flow remain open pending the owner/bootstrap decision. The visual capture issues and browser reading accessibility checks above also remain open.
## Proposal status continuation
The explicit MCP catalog now includes `proposal_status`, `proposal_evaluate` and `proposal_withdraw`; the generated v1 schema includes the bounded status response record. Status returns the proposing agent's lifecycle, validation outcome/findings and durable receipt without returning the stored proposal body. Unknown proposal IDs and proposals owned by another principal both return the same unavailable result. Evaluation applies deterministic validation and authorization without writing a proposal, journal event, receipt or canonical commit. Withdrawal shares the canonical-writer lock, is idempotent, refuses accepted work, and prevents later submission of the same proposal revision. MCP tests cover valid and wrong-location evaluation, no canonical revision advance or status record before submission, author isolation, withdrawal, and denial of another agent's status/evaluation/withdrawal attempts. Recovery tests verify ref-before-receipt recovery reports accepted and prepublication recovery reports staged.
## Local GEWU pack contract and run checkpoint
Pack version 0.3.0 includes a `service-v1.json` snapshot generated from the actual MCP SDK tool inventory, including discovered input schemas, the operation catalog digest and generated v1 record-schema hashes. `test_agent_contract.py` creates a temporary service and compares its live tool schemas with the pinned pack snapshot. `manifest_tool.py verify` checks all module hashes, the module snapshot, nested schema hashes and capability names. `run_checkpoint.py` creates mode-0600 checkpoint files under a mode-0700 `Runs/` directory and atomically updates them; tests record scope/lens, source extraction references, explicit exclusion reasons, uncertain-operation digests, proposal revisions/receipts and output hashes. Resume rejects pack-hash drift, invalid output hashes, mismatched acceptance receipts and secret fields. Domain and MCP tests verify that node/assessment authorship cannot be attributed to a different agent. These are local synthetic checks: native host discovery/workflows, remote service identity, OS process-kill recovery, semantic quality, and the supported OS matrix remain NOT RUN. No project/lens read is exposed; the pack requires explicit user/workspace lens input and reports unavailable P1 capabilities. Backend lint, typing, all 69 tests, boundary checks, pack manifest verification and whitespace checks pass; frontend checks/build pass; npm audit reports zero vulnerabilities.
## Agent-owned service run continuation
The v1 MCP catalog and pack snapshot now include `run_create`, `run_checkpoint` and `run_status`. Run records are private to the authenticated agent principal, require explicit project/shared submission grants, and are stored as mode-0600 files beneath a mode-0700 run directory. Writes are atomic and serialized with identity revocation and canonical publication; creation is idempotent for the same request, while changed input under an existing run ID conflicts. Checkpoints use expected-revision compare-and-swap; identical uncertain retries return the committed revision, changed retries and stale revisions conflict, and completed/blocked runs are terminal. Tests cover create/status/checkpoint through a live MCP session, owner isolation, credential revocation, idempotent retry, changed content and stale revision rejection, and terminal state enforcement. Generated schemas/catalog and the pack contract were regenerated from the service. Local evidence only: host-side automatic run mirroring, native host resume, process-kill recovery, other operating systems and remote service identity remain NOT RUN.
## Project-authorized archived source download
The HTTP reader exposes the original archived source at `/v1/projects/{project_id}/sources/{revision_id}/artifact`. The handler first resolves and validates the canonical source revision and its `ingested_for` project grant, then checks the artifact digest, stored project provenance, media type and byte length before streaming. Responses include a digest ETag, `private, no-store`, `nosniff`, and sandbox CSP headers. The authenticated-read integration test verifies byte-for-byte output, unauthenticated denial, out-of-scope/unknown revision denial, integrity metadata and revoked-credential denial. The route is read-only and does not expose storage paths. A bounded authenticated HTTP slice endpoint returns normalized and original text with the extraction offset map after confirming both the canonical source grant and project-scoped extraction. The reader exposes an exact-location action and archived-download link; its frontend test exercises both controls and renders the captured text. Browser automation snapshot failed repeatedly, so screenshots and native browser interaction are NOT RUN. At the available 391×845 mobile viewport, DOM inspection found no horizontal overflow (document width 376 px). 320 px reflow, 200% zoom, keyboard/screen-reader review, and cross-platform behavior remain NOT RUN.
## Authenticated service diagnostics
The shared typed diagnostic contract is exposed by authenticated HTTP and MCP operations. It reports the live catalog SHA-256, service/API/schema versions, caller roles and readable projects, role-filtered operations for the current transport, optional explicit scope, source transfer size/chunk/media constraints, canonical/index revisions and index state. It reports `authenticated` connection status and `not_verified` workflow status separately. It contains no principal ID, credential identifier or token. HTTP and MCP integration tests verify catalog digest equality, authenticated-only access, project/shared-scope denial, read-versus-agent capability filtering, transfer limits and absent credential fields. The indexed-search integration additionally observes `not_built`, `current` and `lagging` states without diagnostics triggering a rebuild. The MCP inventory snapshot and generated schema/catalog were rebuilt from the actual server. Commands: `make schemas`, `make pack-manifest`, `python agents/gewu/scripts/manifest_tool.py verify`, `make check`, `make typecheck`, `./scripts/python-tool mypy src tests`, `make test`, `make boundaries`, and both root/submodule `git diff --check`. Observed on local Linux/Python 3.14.7: all 69 backend tests, Ruff, both mypy checks, boundaries and manifest verification pass; frontend checks/build and npm audit were rerun during the immediately preceding UI slice and passed (2 frontend tests, zero reported vulnerabilities). This remains local synthetic evidence; native connector/client workflows and installed skill-version verification remain NOT RUN.
### Additive pack installer
The GEWU pack was version 0.5.0 for this installer increment; the current pack is 0.6.0 and now includes a copy-based installer. In isolated temporary workspaces, six tests cover installation and removal, preservation of existing AGENTS/CLAUDE instructions and a Gemini MCP entry, preservation of unrelated skills, refusal to overwrite an occupied pack destination, rollback after a simulated copy failure, refusal to remove a modified owned routing block, and preservation of later user edits and user-added files during uninstall. The installer rejects a symlinked .agents parent and does not configure host MCP entries or store credentials. Commands: make pack-manifest, python agents/gewu/scripts/manifest_tool.py verify, make check, ./scripts/python-tool mypy src tests, and ./scripts/python-tool pytest -q tests/test_pack_installer.py; all passed on Linux/Python 3.14.7.
This is fixture evidence for filesystem behavior only. The installer has not been run in a real project workspace; installed discovery, service connection, active-run pin behavior under a native host, host MCP setup, and workflow verification remain NOT RUN. Existing pack destinations are refused, so an update cannot silently replace a pack pinned by a run.
### Allowlisted URL capture
Added the authenticated MCP operation source_capture_url. The service operator enables destinations with GEWU_FETCH_ALLOWED_HOSTS, a comma-separated exact-host allowlist; empty configuration leaves all fetches blocked. The adapter accepts only HTTP(S) on standard ports, resolves and rejects every non-global address, connects to the validated address directly, rechecks each redirect, disables compressed responses, caps responses at 50 MiB and 60 seconds, and allows two concurrent captures. The MCP handler checks the authenticated agent's project submission grant before fetching, stores UTF-8 text/Markdown/HTML through the existing verified artifact store, and strips query strings/fragments from returned source URLs. Four URL-fetch tests cover allowlisted capture and pinned address use, private DNS rejection, redirect rejection and unsupported/oversize responses. The HTML parser test and authenticated MCP integration cover visible-text extraction, active-content exclusion, normalization maps, successful HTML archive/extraction and cross-project denial. Commands: make schemas, make pack-manifest, manifest verification, Ruff, mypy, focused MCP/schema/adapter tests; all passed on Linux/Python 3.14.7.
This is synthetic fixture evidence. No public source was fetched. PDF parsing, parser process isolation, reference-only failure records, URL identity/revision updates, HTML title extraction, exact location verification against representative pages and native host workflows remain NOT RUN. HTML citation offsets point into the extracted visible text; the parser does not map them to markup byte offsets.
### HTML extraction and final local validation
The versioned parser now archives HTML while extracting visible text, removing script/style/template/noscript content and preserving normalization maps over the extracted text. HTML URL capture and extraction were exercised through the authenticated MCP fixture, including cross-project denial and archived original-byte verification. HTML citation offsets resolve against the stored visible-text extraction; they do not claim raw markup offsets. URL fetching now bounds DNS resolution to five seconds with at most two in-flight resolver tasks, in addition to the fetch duration, size and concurrency limits. The final local run regenerated schemas, catalog and pack manifest, verified pack integrity, passed Ruff, mypy (31 application and 60 source/test files), 85 backend tests, import boundaries, frontend TypeScript/ESLint/Vitest (2 tests), production build, npm audit (0 vulnerabilities), and both root/submodule diff checks. Runtime: Linux, Python 3.14.7, Node 26.8.1.
No public source was fetched. PDF parsing, isolated parser processes, reference-only failure records, URL identity/revision updates, HTML title extraction, real-page exact-location verification, native host discovery/connection/workflows, accessibility/visual qualification, real pilot corpus and owner-approved policies remain open.
## Entity consistency, search facets and reader continuation
The domain normalizes aliases to NFC and collapsed whitespace and rejects empty, duplicate, or title-repeated aliases. Proposal validation flags exact entity title/alias collisions in the candidate's project and across other projects only when both the explicit proposal scope and caller read grants permit comparison. The MCP adapter intersects those grants and scope; the validator independently enforces the explicit scope. A match produces only a generic review finding and prevents auto-accept; it does not create an entity link or merge. Publication rechecks the actor's credential, roles and project-grant snapshot. Tests cover same-domain collision, authorized cross-project and shared matches, excluded-scope/unreadable isolation, grant snapshot comparison and normal MCP contribution flow. SQLite FTS includes aliases. Reversible merge history and protected owner authorization remain unimplemented.
Search now accepts typed node-type filters and a stale-only filter in HTTP and MCP. SQL applies the filters before pagination; cursor fingerprints bind both filters. The reader exposes query, project, type and past-freshness filters in the URL, and separately labels accepted relationships and on-demand lexical suggestions. Canonical note detail exposes exact citations, source locations, recorded claim assessment details, relationship conditions/rationale and history. Frontend tests cover empty/error states, assessment rendering and the relationship/suggestion path.
The source index now supports an authenticated, paginated list_sources operation over HTTP and MCP. The SQL query joins normalized source grants before pagination, so records without a grant in the explicit requested scope are not listed. The UI's Sources navigation loads that bounded catalog and offers only project-authorized archive downloads. Integration fixtures verify list ordering/pagination, denied project scope, and MCP tool behavior; the frontend test covers catalog rendering and download-link construction.
Validation after the source-list and reader changes: schema/catalog/live MCP contract regeneration and pack manifest verification; Ruff; mypy over 33 source files; boundary checks; 102 backend tests; frontend TypeScript/ESLint/Vitest (6 tests); production web build; root and pack whitespace checks. All pass on Linux/Python 3.14.7/Node 26.8.1. T3 preview navigation works at mobile and desktop viewport settings, but snapshot automation still fails; screenshots, keyboard/screen-reader/axe review, 320 px and 200% zoom, native host workflows, real documents, measured retrieval, pilot quality, other OSes and protected owner authorization remain NOT RUN. This evidence does not close M2.4, M2.5, M3 or the release gate.
### Problem reading and recorded facets
Problem detail labels accepted links as approaches and related knowledge, explains when no accepted approaches are visible, distinguishes accepted links from lexical suggestions, and shows recorded tags, audience, use and domain metadata. Knowledge nodes now have explicit `assumptions` and `limitations` groups of ordinary evidence-backed claims. Validation enforces their assessor attribution, assertion/evidence digests and exact source locations; SQLite FTS searches their text; search, canonical reads and history return their citations; the UI renders their evidence type, status, method and rationale under separate headings. Domain tests cover eligible sourced claims and wrong-location rejection; SQLite tests prove retrieval and citation inclusion; the frontend test covers rendering. Multi-problem facet filtering, cross-project relationship explanations and visual/accessibility acceptance remain open.
At a 320×800 CSS-pixel T3 preview viewport, DOM measurement found page scroll width equal to viewport width (320 px); the rail navigation now wraps and scrolls within its own row. Snapshot automation still fails, so this is a layout measurement rather than screenshot or interactive visual acceptance.
### Evidence-backed assumptions and limitations
Added backward-compatible `KnowledgeNode.assumptions` and `.limitations` claim groups. Each entry reuses `Claim`, so it cannot be stored without typed evidence and a support assessment bound to the exact assertion and evidence digests; claim IDs must be unique across all groups, and each evidence reference must identify its group/index path. Acceptance validates source revision, extraction integrity, quote location and assessor attribution for every group; accepted node readers, history, FTS and search citations include them. Tests prove a valid claim is eligible, a wrong-location assumption is rejected, accepted publication persists the extraction and reader returns the typed claim/citation, and SQLite search retrieves the group text with its citation; the frontend test verifies separate assumption/limitation headings and content. Schemas, operation catalog, MCP snapshot and pack manifest were regenerated and verified. Full local verification passes on Linux/Python 3.14.7/Node 26.8.1: 109 backend tests, Ruff, mypy, boundaries, six frontend tests, production build and whitespace checks. This does not complete M3.3's facet navigation, cross-project explanation or visual/accessibility gates.
### Authorized cross-domain duplicate review
Proposal validation now compares entity titles and aliases across projects listed in the explicit proposal scope only when the authenticated principal can read those projects. The MCP adapter computes that intersection, and the validator independently intersects its input with proposal scope. Findings disclose only that a possible duplicate exists; they do not return the matched record. Acceptance carries the actor's role/project-grant snapshot and the identity store rechecks it immediately before publication under the canonical writer lock. Regression coverage verifies authorized project/shared matches, unreadable and out-of-scope isolation, changed authority snapshots, and the normal MCP contribution path. Validation: regenerated contracts/manifests; 106 backend tests pass; Ruff, mypy, import boundaries, six frontend tests, production build and whitespace checks pass on Linux/Python 3.14.7/Node 26.8.1. Reversible merges and protected owner decisions remain unimplemented.
### M0.7 Cross-process writer exclusion
Two separately constructed acceptance-service instances share one repository and workflow lock. The test pauses the first publisher inside its commit section, confirms the second instance receives the stable `BUSY` error, then releases the first and verifies exactly one canonical revision was published and no receipt was fabricated for the rejected writer. The test passes as part of the 106-test backend suite. This proves the local lock boundary for simultaneous writers; it does not replace process-kill recovery, filesystem-specific lock qualification or the full shared-repository adapter contract suite.
### M0.1 CI and automated browser continuation (2026-10-14)
Added `.github/workflows/ci.yml` for pushes and pull requests. It installs Python 3.12 and Node 22, syncs the locked Python and npm dependencies, verifies generated schemas/catalog/MCP contract and the GEWU pack manifest, then runs backend lint/type/boundary/tests, frontend check/build, and Chromium browser tests. `make browser-test` runs the same browser suite locally. Playwright artifacts upload when a CI job fails. The hosted workflow has not run yet, so CI execution and Python 3.12/Node 22 compatibility remain unverified.
The two Chromium tests use a routed synthetic read API and a real browser rendering the authenticated UI. One restores project, query and tag/audience facets from a shared URL, opens a result, verifies its exact citation and checks a 320 px viewport. It exposed a 40-character canonical revision expanding the page; reader metadata now wraps on narrow screens. The other confirms editing a query does not issue a search until the user submits it. Vitest discovery explicitly excludes Playwright files, keeping unit and browser runners separate. Local verification passes: 121 backend tests, 13 frontend tests, two Chromium tests, TypeScript, ESLint, Vite production build, Ruff, mypy (33 source files), boundaries, generated contracts, pack manifest and whitespace checks. The contract suite also rejects traversal-like, slash-containing and whitespace-prefixed project IDs through scope validation. These browser tests do not replace live-backend browser coverage, accessibility review, visual protocol screenshots or cross-platform acceptance.
### M0.2 Generated read API types and allowlist continuation (2026-10-14)
Added a deterministic OpenAPI exporter that composes the real local HTTP application under a temporary `GEWU_DATA_ROOT`, so schema generation cannot initialize or modify an operator's data. It adds canonical record schemas as components with rewritten local definitions; `openapi-typescript` generates `web/src/generated/api.ts`. HTTP route operation IDs now match the explicit transport operation catalog, and an integration test asserts exact set equality plus the exclusion of proposal and owner writes. The reader imports generated envelope, citation, source and request types and uses `satisfies` checks for its search, neighbor and source-list request bodies. Browser fixtures now include the required envelope and citation contract fields.
`make api-types` regenerates OpenAPI and TypeScript. CI runs it with `make schemas` and fails on generated drift. The contract audit remains partial because the PRD's full contract inventory and tokenizer/profile decision are not closed. OpenAPI generation is locally exercised against the composed app; hosted CI and the chosen codepoint/tokenizer semantics remain separate evidence gaps.
### M0.3 Cross-project policy fixture continuation (2026-10-14)
Added a deterministic source-registration fixture ingested for both pilot projects plus shared. The same proposal publishes a Dome datapoint with exact source evidence while naming both project scopes. It is eligible only when the Dome, interactive-video, and shared policies all apply; disabling source auto-registration in the video policy yields `needs-review` and prevents auto-acceptance. Together with existing wrong-location, supported-quote/unsupported-assessment, stale-assessment, missing-policy and scope-escape tests, every deterministic M0.3 example now has an explicit expected status/finding. Ruff, boundary checks and all 123 backend tests pass.
This fixture proves the cross-policy evaluator, not semantic assessor quality. The PRD's 20 hand-guided real sources, deep-research report and labeled expected-answer questions remain external inputs; synthetic cases do not close that pilot gate.
### M0.4 Upload integrity and interruption continuation (2026-10-14)
Added explicit artifact-store checks for a chunk digest that does not match its bytes, a completed upload whose whole-artifact digest differs, and an interrupted multi-chunk upload that cannot publish or expose the expected artifact. Extended the authenticated MCP source-to-citation vertical slice: premature finalize fails, `source_extract` cannot read that unfinalized artifact, a wrong chunk digest is rejected, and the same bytes subsequently upload, finalize and extract successfully. Existing coverage verifies matching chunk retry after adapter restart, text/Markdown normalization maps, immutable extraction records, shared artifact deduplication with two project grants, and explicit unavailable PDF extraction. The focused MCP flow passes. A symlink regression test confirms forged session directories and chunk symlinks are not followed; the full backend gate now has 127 passing tests. M0.4 local acceptance is complete; NotebookLM, cross-platform/parser qualification and real-source locator evaluation remain under the later pilot/input-coverage gates.
### M0.5 Mandatory policy validation continuation (2026-10-14)
Added a regression case proving `require_supported_assessment=false` is treated as a policy violation and cannot make an otherwise eligible proposal acceptable. Existing deterministic coverage verifies correct quote with unsupported assessment, exact-location mismatch, stale assertion assessment, evidence and author binding, scope escape, edge policy, and eligibility across every affected policy. The MCP source-to-citation integration verifies a failing proposal is retained as evaluated without a receipt, while its valid correction is eligible and accepted by policy. Ruff, import-boundary checks and all 126 backend tests pass. This satisfies M0.5's local acceptance checks; semantic assessor quality and complete merge workflow remain separately open.
### M1.1 Role enforcement and publication revocation continuation (2026-10-14)
The real MCP contribution test now provisions a viewer with the same project grants as an agent and confirms the viewer cannot submit proposals or begin uploads. A publication test uses the SQLite identity store and revokes the agent key between initial validation and the final publication check; submission fails with `POLICY_CHANGED`, canonical HEAD does not advance, and the proposal remains evaluated without a receipt. Ruff, mypy, import-boundary checks and all 128 backend tests pass.
M1.1 remains partial. The protected owner CLI/session/challenge profile in the architecture is proposed, not an approved live mechanism; named project/shared owners and the first-owner bootstrap authority were not supplied. No unprotected challenge endpoint or inferred owner grant is added while those authority inputs remain unresolved.
### M1.3 Remote connector service identity continuation (2026-10-14)
The remote connector HTTP client now explicitly sets certificate verification before using its operator-provisioned bearer credential. A focused factory test enters the actual remote-client context and checks that the configured endpoint is HTTPS, verification is enabled, and the credential is attached as an authorization header rather than placed in the URL or tool result. The full Python quality gate passes with 129 backend tests, Ruff, mypy (33 source files) and import-boundary checks.
This is local contract evidence only. A live remote HTTPS service, deployed certificate and native host connection are not available here, so M1.3 remains partial.
### M3.1–M3.2 Keyboard path continuation (2026-10-14)
The Chromium reader flow now focuses a search result and opens it with Enter, then verifies the exact cited evidence is visible. The search-submission flow presses Enter in the query field and confirms that no request is sent before submission and exactly one is sent afterward. Both browser tests pass. This adds keyboard activation evidence for the main search-to-citation path; it does not establish complete tab-order, zoom, screen-reader or accessibility acceptance.
### M0.7 Independent Git writer race continuation (2026-10-14)
Two separately constructed `GitCanonicalRepository` adapters start publication from the same expected head at a barrier and write distinct record paths. The compare-and-swap on the shared Git ref admits exactly one commit; both adapters observe that head, and the losing writer's path is absent from the winning tree. The test passes on the full 130-test backend suite, with Ruff, mypy and import-boundary checks. This proves the adapter-level race boundary for Git; it does not expand the shared replacement contract or filesystem/platform qualification.
### M2.2 Active-run pack-upgrade boundary continuation (2026-10-14)
Added a checkpoint test that creates a run under the current manifest, then supplies a simulated newer manifest with a changed module implementation and recomputed snapshot digest. With the new manifest treated as verified, resume fails with the pack-changed error and leaves the old checkpoint bytes intact. The full Python gate passes with 131 backend tests, Ruff, mypy (33 source files) and import-boundary checks. This verifies local checkpoint pinning; native clients still need installation/update and resume workflow qualification.
### M1.4 / FR-U2 Confidence and as-of date search (2026-10-14)
Added optional confidence values and inclusive `as_of` date bounds to the strict search request contract. SQLite applies them before pagination; the scoped cursor fingerprint includes all three values so changing a filter invalidates an existing cursor. HTTP and MCP searches exercise the filters against a fixture with distinct as-of dates, and domain validation rejects reversed ranges and repeated confidence values. The reader exposes labeled confidence checkboxes and date inputs, persists them in the URL, restores them from shared links and browser back/forward, and submits them with search. Frontend tests verify the request body and history restoration; Chromium verifies restoration from a direct URL at a narrow viewport. Generated schemas, OpenAPI, TypeScript types, service contract, and pack manifest were regenerated. Backend checks pass with 131 tests; frontend checks pass with 13 tests, build, and both Chromium tests.
This closes the previously missing FR-U2 confidence/date filter behavior for the implemented lexical reader. Native-client and pilot usability evidence remain under M2.5/M3.4.
The acceptance ledger now includes a separate status row for each of the 33 PRD P0 feature requirements, in addition to milestone and v1 release gates. It identifies FR-U2 as locally complete, retains partial/not-run statuses where implementation or real-host/pilot/deployment proof is missing, and keeps the PRD default-scope decision open under FR-P2. The matrix links each requirement to its current test evidence and remaining proof; it does not claim a P0 release pass.