1
0
Fork 0
Code Issues Pull requests Projects Releases 2 Packages Wiki Activity Actions Pages
DocForge2/docs/CONTRACT.md

15 KiB

DocForge post-1.0 development contract

Authority boundary

DocForge is bound to one explicit project root. Canonical project files own documentation facts. Indexes, query results, context packs, changesets, previews, and renders are derived artifacts.

The generic core validates and retrieves canonical nodes. A project-bound proposal service writes isolated changesets. A separately gated canonical application service may apply one exact, hash-approved changeset through a generic or project-owned serializer. Project builds, Git mutation, deployment, and publication remain external. Passive revision detection may read the current Git commit when Git is available; it cannot change repository state.

Versioned contracts

  • Project descriptor schema: schemas/project.schema.json, version 1.
  • Node schema: schemas/node.schema.json, version 1.
  • Edge schema: schemas/edge.schema.json, version 1.
  • Result envelope: schemas/result.schema.json, version 1.
  • Changeset schema: schemas/changeset.schema.json, version 1.
  • Index schema: version 1, disposable and reproducible.
  • Core, CLI, and MCP server: version 1.1.0.dev0.
  • Incremental extraction cache: version 1, disposable and reproducible.

Schema files describe the generic interchange contract. Runtime validation remains responsible for path confinement, source hashing, relationship resolution, dependency cycles, project limits, stale state, and adapter-specific rules that JSON Schema cannot prove by itself.

Generic node storage

Markdown nodes begin with a TOML metadata block delimited by +++. The remaining Markdown is the node content. TOML sources contain one or more [[nodes]] tables and store content in a content field. Every node has a stable project-wide ID.

The generic authority vocabulary is authoritative, approved_plan, derived, proposal, and historical. Projects define statuses and allowed relationship names in their descriptor. The core gives special acyclic validation to depends_on; adapters may add stricter rules.

Result identity

Successful operations identify the project, adapter, current revision when available, and canonical source hash. Errors use a stable code, direct message, and structured details. Query operations fail if canonical source no longer matches the derived index.

Isolated proposal model

Create, update, move, and delete are ordered node operations inside an isolated changeset. Every operation names its expected base hash. A move preserves the stable node ID. A delete must resolve every incident relationship. Proposal validation and storage are atomic. Application requires the exact final changeset hash; prose is never auto-merged.

Relationship-only additions and removals use the validated update operation without changing node metadata or content. They remain bound to the complete changeset base hash and the anchor node's expected content hash.

The MCP process binds to one configured writer identity at startup. The project descriptor grants that writer explicit families and operation types. A changeset records its creator, project root fingerprint, base revision, canonical source hash, and ordered operations. Every append requires the current changeset hash, so simultaneous writers cannot silently lose an operation.

Changesets from the same canonical base may coexist only when their touched node and source sets do not overlap. Exact overlaps return structured conflicts naming the other changesets, nodes, and sources. A stale canonical base, stale node hash, stale changeset hash, unauthorized family, unsafe path, invalid graph, dependency cycle, unresolved delete relationship, or configured limit fails before the proposal file changes.

Declared rendering and previews

Render configuration is optional. A configured project declares one template root, one isolated preview root, and one or more stable view IDs. Each view names a built-in renderer, template, derived output file, title, and optional family filter. Paths are resolved under the project root and may not overlap canonical content, authority files, changesets, templates, or previews.

The initial generic_html renderer uses pinned CommonMark parsing with raw HTML disabled. Templates are UTF-8 files with a fixed token vocabulary; they cannot name commands, modules, or executable renderers. Render identity covers the canonical source hash, optional changeset hash, selected node and edge identities, view configuration, template hash, renderer contract, and exact parser version.

An explicit CLI render atomically replaces one declared derived output. MCP can render a validated changeset only to its isolated preview path. Status recomputes expected output without writing and reports current, stale, missing, unsafe, or oversized. Input changes detected before atomic replacement fail without replacing the prior output.

Normal MCP access does not expose canonical application. An explicitly configured canonical applier registers one hash-bound application tool. No MCP mode exposes arbitrary renderer execution, arbitrary file writes, shell commands, Git mutation, build commands, deployment, or publication.

Project-bound graph visualization

The fixed docforge_visualize MCP tool starts one persistent read-only graph browser for the server's already-configured project. It accepts only an optional stable node ID, an optional lexical query, and a bounded traversal depth. It does not accept a project root, database path, SQL, template path, bind address, command, or renderer.

The runner validates the complete canonical projection and derived index before it starts. It then pins the browser to that exact validated SQLite file identity and project metadata so normal UI queries do not rebuild a large adapter graph. Replacement or alteration of the index file makes the browser fail closed; the user must invoke the tool again. The browser identifies itself as a validated snapshot rather than claiming that canonical files are continuously monitored.

The HTTP listener binds to 127.0.0.1 on an operating-system-selected port. A cryptographically random token is part of every accepted URL path. Only GET and HEAD are supported. Responses use no-store caching, a restrictive content-security policy, frame denial, MIME sniffing protection, and no-referrer policy. The built-in template uses only same-origin JSON endpoints for graph overview, bounded search, exact descriptor-category filtering, exact node content, bounded incoming-and-outgoing neighborhoods, semantic Flow ancestry, convergence Web context, and one node's bounded project-confined source file. Descriptor filtering accepts only family, authority, status, or tag plus one exact value. There is no write endpoint, arbitrary query endpoint, static filesystem handler, external asset, or project-selection control.

The graph-browser@15 template provides mouse-wheel zoom centered on the pointer, left-button drag pan, explicit zoom-in and zoom-out buttons, a reset-view button, and a live zoom percentage. A four-pixel drag threshold defers pointer capture and preserves node activation for ordinary clicks. Loading another root node fits the viewport to the returned neighborhood, including a useful minimum scale for a single-node result. The current root begins selected, and activating another graph node moves the visible selection ring to it. Space centers the viewport on the selected node without changing zoom. Reset restores the fitted neighborhood view. Empty-canvas guidance is hidden whenever a neighborhood is rendered. The page is fixed to the browser viewport. Search and exact filter results fill the left panel, neighborhood traversal fills the right panel, and only the center SVG canvas pans or zooms.

Canvas nodes are semantic cards. The focus and relation-derived Structure, Behavior, Dependency, Execution, Data, Evidence, Context, and Related categories have distinct rails and badges. Cards display the readable leaf title and node kind. Long titles wrap instead of being clipped. The complete qualified title and stable node identifier remain available in the SVG tooltip and node inspectors. This display shortening is presentation-only and never changes indexed identity.

Left-clicking or pressing Enter on a graph node opens a compact descriptor card containing the validated metadata and content previously shown in the details panel. Its family, authority, status, and tag pills are buttons that replace the left result list with exact matching nodes. Right-clicking or pressing Shift+Enter opens the complete inspector. Inspection does not replace the current neighborhood or reset the viewport. Both dialogs support Escape, explicit close controls, and backdrop dismissal. Loading the inspected node as the new root requires the separate Explore neighborhood action. Non-focus nodes may be hidden from the presentation and restored without mutating graph state. Flow and Web recompute focus reachability after each hide so disconnected upstream-only branches are pruned while downstream convergence remains visible. Source actions open the project-confined source and navigate to supported line, TOML, heading, or text anchors. Both side panels support pointer and keyboard resizing. The unblurred full inspector supports native resizing, constrained title-bar dragging, and a fixed header/footer surrounding a scrollable body.

The header exposes a Nodes/Flow/Web segmented selector. Nodes displays the complete bounded neighborhood. Flow displays semantic ancestry ending at the current root. Structural and execution edges retain their declared source-to-target direction. Reads, imports, dependencies, inheritance, and tested_by reverse because their declared target feeds or qualifies the source. Documentation and context relations remain available in Nodes and Web but are excluded from Flow. Web follows all relationship types as bounded semantic contributors into the current root. It also reverses direct root-owned members and execution dependencies into adjacent contributor branches. Traversal does not fan back out through unrelated siblings. These are presentation transforms over the validated snapshot; they do not add or change project relationships.

All three views color edges by relationship semantics and retain direction with visible SVG endpoint symbols. Line patterns provide a non-color cue. A static canvas key shows the exact symbol, color, label, and visible count for each displayed relation, including a deterministic fallback for project-defined relations. Nodes, Flow, and Web use the same map.

The browser derives node presentation roles only from the returned bounded graph. The current root is the focus. In Nodes, nodes reachable through outgoing edges are shown as outgoing paths; the remaining visible nodes are incoming or lateral context. In Flow, lineage predecessors are shown as upstream nodes. In Web, all retained contributors share the convergence role. These roles receive distinct palettes and navigation sections. An undirected shortest-hop calculation places Nodes on distance rings; Flow and Web use left-to-right distance layers with the destination on the right. Each role palette darkens progressively by distance, capped at fifty percent.

Each invocation creates or reuses one worker through the separately supervised, per-user viewer manager. The manager is outside the short-lived MCP transport and owns all child workers as one OS service unit. It accepts only authenticated loopback requests and a validated immutable snapshot. A repeated invocation reuses its unguessable URL when the snapshot is unchanged. If the index has changed, it replaces the worker only after a fresh complete index check.

docforge_visualization_status reports the managed worker state. docforge_stop_visualization explicitly stops the current project's worker. The manager applies a one-hour activity timeout to genuinely abandoned workers. Browser activity renews that timeout, but normal MCP transaction or host-process completion does not affect it. The manager itself is restarted by an OS-native, per-user supervisor. Project-specific integrations receive the same tools because the parent validates and serializes only the supplied ProjectService and ProjectIndex snapshot; workers do not discover projects or load canonical sources.

Project adapter boundary

An adapter supplies one deterministically ordered AdapterProjection containing core nodes and edges plus ordered adapter metadata. The core validates root identity, graph integrity, stable ordering, and metadata-key uniqueness before exposing the projection through the standard derived index. The loader is called again during an operation so identity or source changes fail closed.

Adapters own stricter project semantics such as authority precedence, phase rules, context selection, query ordering, and render-model composition. They may not weaken root confinement, canonical authority, graph validation, hashing, stale-state checks, or derived-output boundaries. Shadow adapters are explicit local integrations and are not loaded by the normal generic MCP process. A project integration may explicitly construct a read-only MCP server from one validated ProjectService and an optional project-owned context provider. That server exposes only the fixed read tool surface. The core does not discover adapters, choose projects or sessions, or import project policy.

A proposal-enabled adapter declares confined canonical source, changeset, template, preview, and render paths plus fixed writer permissions. It must supply a proposal validator. The core continues to enforce optimistic hashes, writer permissions, graph integrity, limits, atomic changeset storage, conflict detection, and preview confinement. The adapter validator enforces source-format and project semantics that the generic core cannot infer. Generic projects retain the built-in Markdown and TOML source-layout validator.

An explicit integration may construct the full fixed MCP surface for a configured adapter project and one startup-bound writer. Canonical application is registered only when the integration also supplies a startup-bound applier identity and project-owned CanonicalApplier. An adapter without proposal settings or validation remains read-only.

An adapter may additionally implement the opt-in incremental contract. Its manifest inventories stable source IDs, fingerprints, extractor versions, and source dependencies without parsing the complete project. Each extraction owns deterministic nodes, relationships, and optional function-scoped logic. Added, changed, deleted, and reverse-dependent sources are invalidated. Cached and refreshed facts are always assembled into a complete projection and pass normal graph validation before publication. The full projection loader remains the fallback and equivalence oracle.

The Release 1 AdapterLoader contract remains valid. A loader that supplies only load_projection() stays on the complete-projection path. Incremental capability detection is additive and cannot make the new methods mandatory for an existing adapter. An incremental loader must also implement load_projection() so a clean rebuild and equivalence check remain possible.

Logic projections are not primary graph nodes. They remain source-scoped, function-owned, independently cached control-flow data so ordinary search, Nodes, Flow, and Web do not become statement graphs.