Graph inspection

Cogitatum 0.5 provides a plain-text inspection view of one compiled graph. It exposes individual Points and Bearings without reconstructing the author’s document or evaluating its reasoning. This page specifies the structure-v1 projection and graph-text version 1 retained by the Core/CLI 0.6.0 checkout. The notation version stays 1; note records and their prose remain outside this bounded structural view. The projection is the bounded preservation contract for the first inspection view; broader source rewriting and theoretical interpretations require their own contracts.

Inspect a document

Build the source checkout, then run:

npm run cog:dist -- graph --format text inquiry.cog.md

Installed CLI packages expose the same operation as cog graph --format text inquiry.cog.md. cog graph reads source, parses it and compiles its Points and Bearings. Its name identifies the result to inspect, just as cog ast identifies the parsed source tree. cog check and cog explain also compile, returning diagnostics and a compilation trace respectively; there is no separate compilation step to run first. --format selects the output representation of that compilation: JSON by default, or the text projection below. cog graph and cog graph --format json return the same JSON output. The JSON data’s version identifies the compiler format contract; the CLI’s --format json|text option does not select a language version. Neither option rewrites source or calls an LLM. For an already compiled Graph IR in a program, call Core formatGraph(graph); the CLI’s file argument expects source rather than saved Graph IR JSON. Graph text inspection accepts document input only. Host input can contain several independent source units and source-selection errors; use its complete JSON envelope rather than silently formatting one surviving graph.

For example:

- [C @claim] The bridge is safe.
  - [G @inspection; @route] Yesterday's inspection found no defects.
- [O -> @route] The inspection omitted the underside.
cogitatum-graph-text 1
format: "0.6.0"
projection: structure-v1
status: no-errors

points (3):
p1: role(C) id="claim" text="The bridge is safe."
p2: role(G) id="inspection" text="Yesterday's inspection found no defects."
p3: role(O) text="The inspection omitted the underside."

bearings (2):
b1: supports([p2], p1) handle="route"
b2: challenges([p3], b1)

diagnostics (0):

The second relation targets b1, the inspection step; targeting p1 would challenge the claim itself. supports([p2, p3], p1) would be one joint step, whereas two separate Bearing rows would remain two distinct steps. A Serial structure retains its intermediate Point and each step; the formatter adds no transitive support.

Structural contract

For format 0.6.0, a graph has finite, disjoint typed identity sets of Points and Bearings. Each Bearing has a nonempty, duplicate-free, ordered sequence of Point sources and one typed Point or Bearing target. supports, challenges, concerns and clarifies admit either target type; answers and respondsTo require a Point. Point declaration metadata is role with its role, or material without a role. Neither form carries an open or resolved status. Authored names are separate from compilation-local keys. Refer to the machine contract for field definitions and source-unit scope.

Schema validity checks JSON shape and local restrictions. A well-formed graph additionally needs unique identities, resolved typed references and source uniqueness by identity. Compiler-produced graphs also reflect a particular source and its compilation rules; schema validation alone does not establish that provenance or agreement with source. The formatter consumes current compiler-produced Graph IR, not arbitrary unvalidated JSON. It rejects an unsupported version, duplicate typed keys, dangling references or an invalid source set rather than printing guessed endpoints. These checks protect the representation; they are not a complete graph validator.

Identity remains significant even when two Points have identical text or two Bearings have identical kinds and endpoints. Sources retain their order without treating that order as a sequence of inference. Isolated Points, shared premises, intermediate Points, self-references and cycles remain representable. A cyclic reference prints a label rather than recursively expanding the target. A Bearing-targeted challenge addresses that individual relation, including a joint relation; it creates no extra member-to-conclusion supports. No graph row asserts truth, logical validity, defeat, acceptability or resolution.

What structure-v1 preserves

Graph information Treatment
Format version Printed explicitly
Each Point and Bearing identity Replaced by a distinct output-local pN or bN label, used consistently in every reference
Point declaration, text, optional id Preserved; declaration records its form and applicable role
Bearing kind, ordered sources, typed target, optional handle and text Preserved, including separate instances with equal endpoints
Optional name/text absence versus empty string Preserved by omitting the field or printing =""
Point and Bearing array order Used to allocate and print labels; no sorting or deduplication
Compilation key spelling Omitted; labels do not promise persistence between exports or revisions
Entity sourceSpan and Bearing derivedBy Omitted from the structural projection
notes source/target records Omitted; identical structure text does not establish equal object notes
Diagnostics Reported separately in original order, including severity, code, message, optional span and explanation
Original source, ordinary body, note prose and literal subtrees, use-occurrence prose and marks, AST target requirements, Explain trace Not part of Graph IR and not reconstructed

Always retain the original input, input mode, compiler/package version and complete source envelope when source fidelity or reproducibility matters. A graph-only export cannot recover omitted context or distinguish two source spellings that compile to the same graph. For example, [G] and [G +> ^] compile the same Bearing, but AST records whether the mark supplies the relation or the author wrote it out. Changing the mark later therefore changes the first relation and leaves the second as written.

Comparison boundaries

A structural comparison under structure-v1 applies within one format version to graphs without error diagnostics. It permits a separate bijection of Point identities and Bearing identities, preserving every Point’s declaration, text and optional name, and every Bearing’s kind, ordered sources, typed target, optional handle and text. It may ignore compilation-key spelling, entity array order, entity spans and derivedBy. Diagnostics must still be reviewed separately; a matching surviving subgraph cannot make a failed compilation equivalent to a deliberate omission.

This defines a comparison scope, not a public comparison algorithm. Text output is deterministic for the same graph and notation version, but isomorphic graphs with different array order need not produce identical strings. The notation is not a canonical graph hash or a decoder-backed interchange format. JSON remains the machine interchange representation.

Adding an anchor changes retained authored identity metadata, so that edit does not preserve this projection unchanged. Reordering a Bearing’s source list also changes it. Changing a Point’s declaration from C to G changes it even if the connections remain the same. Conversely, a local and explicit form may preserve the projection while changing occurrence prose, literal boundaries or future attachment behavior. The reconstruction comparisons show how Linked and Serial arrangements differ; they do not license arbitrary outline rearrangements.

Text and diagnostic rules

Labels are assigned in array order, starting at p1 and b1, independently of authored names and raw key spelling. An authored name such as p1 is printed as id="p1" or handle="p1"; it never replaces an output label. Fields containing arbitrary text are JSON-quoted without Unicode normalization. Control and format characters, including bidirectional overrides, and Unicode line/paragraph separators are escaped as UTF-16 \uXXXX sequences. Each entity occupies one physical line; literal backslashes and quotes cannot introduce extra records. Output uses LF line endings and one final LF, without terminal colour sequences.

status: no-errors means only that the supplied graph contains no error diagnostic. Warnings and suggestions remain visible; absence of errors does not certify a complete or successful argument. status: partial means error diagnostics exist, so the displayed graph may omit rejected constructions. All supplied diagnostics are printed, including those on an empty graph. The CLI retains exit status 0 for no compilation errors, 1 for compilation or I/O failure, and 2 for invalid arguments. Argument errors retain JSON diagnostics even when text output was requested.

Review names before a deliberate edit

The CLI offers cog check --references inquiry.cog.md to inspect written references before renaming an observation or reviewing which names to retain. Run it on the complete file; use --input host for Markdown. This is a read-only inventory, not an automatic cleanup rule.

Here both Points participate in a connection, but neither name has a written reference:

- [C @sampling] Wait ten minutes before sampling.
  - [G @measurement; @route] Drift was below 0.1% after ten minutes.

The connection comes from indentation. The inventory lists sampling, measurement and the Bearing handle route, each with an empty reference array. That does not justify removing them: a host or a later revision may rely on those names.

Conversely, this measurement has a written reference even though it participates in no Bearing:

- [. use @measurement] Revisit the calibration record.
- [. @measurement] Drift was below 0.1% after ten minutes.

The inventory records the forward Point use on the first line. This is complete without a Bearing or an isolation diagnostic. Ordinary prose mentions and literal note descendants do not count as syntax references.

Point uses, Bearing uses, explicit ordered sources and explicit targets appear separately in the inventory, with their containing block locations. Each host fence has its own namespace. If any selected input has errors, including an omitted unclosed or nested fence, the inventory is explicitly unavailable rather than reporting zero references. Names with no written references generate no new warnings, and the command never edits the source.

Compare commitments across revisions

A structural comparison asks whether two graphs are the same. A commitment comparison asks what a revision retracted and what it added. It distinguishes a refinement, which only adds, from a revision, which also retracts.

A commitment is a relation kind, an unordered set of sources and a target. Several Bearings may state one commitment; they stay distinct entities when something addresses them. Entailment between commitments has exactly two rules:

Only relevance distributes. Joint support gives no member support of its own, separate supports are not one joint support, and bearing on a step is not bearing on its conclusion. Linked support is therefore a commitment of its own, while grouping under [_] adds none: [_] leaves open how its members bear, and refining it may decide that they bear together, separately or with a further premise. A grouping still matters as an entity when another relation addresses it. So [_] refined to [_ +> ^], or split into sibling [G] occurrences, is a refinement, while merging two [G] into one [_ +> ^] is a revision. Selecting a Point is also counted: adding one refines and removing one retracts.

Before After Relation
[_] with members a, b [_ +> ^] with members a, b refinement
[_] with members a, b [G] a and [G] b refinement
[G] a and [G] b [_ +> ^] with members a, b revision
[_ +> ^] with members a, b [_] with members a, b weakening
[_] with member a [_ +> ^] with members a, b refinement
[_] with members a, b [_] with member a weakening
[O/] on a step [O] on its conclusion revision
[G] [G +> @claim] equivalent

Comparing two revisions requires knowing which entity continues which. Core does not infer this silently. suggestCorrespondence(before, after) proposes pairs by authored name, unique text and continued endpoints, lists every entity with several plausible continuations, and never chooses among equals. An edit tool knows what it moved and passes its own correspondence to compareCommitments(before, after, correspondence). Continuity establishes identity only: a continued Point whose text or declaration changed is reported, not weighed. Graphs with errors, other format versions and invalid correspondences are indeterminate.

The order classifies recorded connections and Point selection, never whether a reading is correct. equivalent is limited to those commitments: a continued Point can change from a question to a claim, or change its wording, without changing this classification. The result reports changed Point content and declarations for separate review; it does not judge their meaning. Notes, body prose, names, marks, source order and positions are outside this order, and changes to them may still alter how the argument is read.

Preview relation edits

cog relation-edit --line 2 --decide supports inquiry.cog.md
cog relation-edit --line 2 --separate inquiry.cog.md
cog relation-edit --join 2,4 inquiry.cog.md

Three edits change recorded relations without touching Point text:

Each preview knows which entity continues which, so it supplies its own correspondence to compareCommitments and reports the resulting relation. The author sees whether the edit is a refinement, which only adds, or a weakening or revision, which retracts something already recorded. So deciding [_] as joint support, or separating it into supports, is a refinement; joining two supports is a revision.

The preview recompiles the complete proposed source. It is unavailable when the input or result has errors, when Points would be added, removed or reworded, or when anything beyond the edited relations would change. Groups with a handle, a description or children other than members cannot be separated, and relations with a handle cannot be joined, because another relation may address them as entities. Q and C occurrences cannot be joined either: a member keeps only its operand, and their marks also declare the Point. Core provides previewRelationEdit(source, { operation, line | lines, kind?, mode? }); the command prints JSON and never writes to the input file.

Preview named and positional targets

cog target-form --line 3 --to named inquiry.cog.md
cog target-form --line 3 --to positional inquiry.cog.md

Every relation ends in one target term: a name, or the positional ^ / ^/ that the outline resolves. target-form previews exchanging one for the other in the occurrence on the given line. The line is one-based in the complete input file; add --input host for a selected Cogitatum fence in Markdown. Selecting a continuation line locates the same occurrence and edits its first-line annotation. Core provides previewTargetForm(source, { line, form: 'named' | 'positional', mode? }). The command prints JSON and never writes to the input file.

An editor offering several choices can call analyzeSourceEdits(source, mode?) once. Its preview(request) accepts { kind: "target-form", line, form } or { kind: "relation", edit }, using the same checks as the standalone previews. It reuses the original analysis and recompiles each proposed source independently. diagnostics, preview results and siblingsAt(line)’s { lines, index } are detached values; literal note descendants are not selectable occurrences. The editor chooses which requests to offer and in which order, and analyzes a new snapshot after an edit. Applying a preview still requires the exact original source and the editor’s revision checks.

Before the edit, the Ground below selects the Claim through ordinary body:

- [C @claim] The service needs inspection.
  - Evidence collected this morning
    - [G; @route] Two independent retries timed out.
      - [O/] Both may share a transient fault.

--to named writes the target that [G] currently abbreviates:

- [C @claim] The service needs inspection.
  - Evidence collected this morning
    - [G +> @claim; @route] Two independent retries timed out.
      - [O/] Both may share a transient fault.

The same three Points and two individual Bearings remain, including the objection to this particular route. --to positional on the second document restores the first; the two directions are one edit read both ways. It does not decide whether the observations are independent or sufficient.

The edit changes only the target term, and the relation or selector slash it needs. A mark’s default relation is written out when its target is named, and omitted again when the result is the mark’s own default: [G +> ^] becomes [G], and [O -> ^/] becomes [O/]. For a constructor, only the header’s target changes; its members stay where they are, still its sources. Spacing, names, handles, prose, note boundaries and line endings are retained.

This deliberately changes future editing behavior. A named target stays fixed when the occurrence moves; a positional one follows the nearest Point or exposed Bearing. A written relation stays when the mark changes; an abbreviated one follows the mark. The consequence text states both effects for the chosen edit. Choose this operation when that is the intended commitment; it is not an automatic formatting fix.

The preview declines errors anywhere in the input, including an invalid or unclosed separate host fence, anonymous targets, occurrences that state no relation (. and C), a source member of a constructor (select the constructor instead), and a target that is already in the requested form. A positional target must resolve to the same entity at the occurrence’s position. No missing premise, new authored name or role interpretation is supplied automatically.

A ready result includes originalSource, proposedSource, one edit with a UTF-16 offset, exact remove text and insert text, both diagnostic lists, and the consequence. The edit is the minimal one between the two annotations. Before applying a saved preview, an editor or caller must compare the complete current source with originalSource; any difference requires a new preview. An unavailable result contains a reason and message, with no edit or proposed source. Exit status is 0 for a ready preview, 1 for an unavailable preview or I/O failure, and 2 for invalid command options.

The Core implementation reparses and recompiles the proposed complete input in the same mode. It checks the ordered AST including occurrence text and note subtrees, allowing only the selected clause to change. It checks every graph’s identities, entity order, contents, declarations, ordered sources, typed targets and names, allowing only the selected Bearing’s structural/operator provenance to change. Diagnostics retain their ordered severity, code and owning occurrence, except that implicit-through-body advice may appear or disappear. These checks establish the stated structural and source preservation conditions; they do not certify an interpretation of the prose.

The published explicit-target command and previewExplicitTarget were retired in 0.6: the command now reports RETIRED_COMMAND and points here.

Inspect every local decision

cog explain --format text inquiry.cog.md
cog explain --input host --format text notes.md

Explain text shows every active occurrence and every compiler effect: its selected context, ordered sources, typed target, reuse, note ownership, joint membership or commentary, and why a Bearing was emitted, skipped or rejected. It distinguishes a failed candidate from a surviving graph entity. Ordinary body crossings and failed nearest contexts stay visible; nothing silently searches outward. Literal note descendants remain owned by their note header and have no active decisions.

A constructor member’s syntactic eligibility and the header’s outcome are reported separately. Explain names the surviving Bearing that includes the source, or states that the rejected header created none. Unlike graph text, Explain text accepts host input. It prints each independent selected unit and all aggregate diagnostics, including an unclosed fence that produced no unit. Names and compilation-local keys are shown with source locations. The header cogitatum-explain-text 1 identifies this readable trace notation; it is not a source formatter or interchange decoder. Core provides formatExplain(explainSource(source, mode)) and EXPLAIN_TEXT_VERSION. JSON Explain and the complete export envelope remain available.

The View package’s Reading presents the same evidence beside the source: selecting a row draws a rail from the context row that indentation selected, marks crossed body, and states the decision in one line, such as From indentation: challenges @g (L2), the nearest enclosing Point. It also distinguishes how the relation is stated: [G] supplies it through the mark, [G +> ^] through a written clause, and [_] through the constructor’s concerns default. Moving a positional occurrence can change its target; changing a mark does not override a written clause. Rows that create no relation say so, including bare C and neutral Points. A nested Q instead records concerns toward its nearest Point.

Core API and compatibility

import { compileGraph, formatGraph, GRAPH_TEXT_VERSION, parseDocument } from '@cogitatum/core';

const graph = compileGraph(parseDocument(source));
const text = formatGraph(graph);

formatGraph(graph: GraphIR): string is pure and operates on exactly one graph. It performs no parsing, repairs, inference or source rewriting. When calling it on a graph extracted from a host envelope, the caller must separately retain and surface the envelope’s aggregate diagnostics and unit scope. The CLI deliberately rejects host graph text until a batch representation is specified.

GRAPH_TEXT_VERSION is "1"; it identifies the notation independently of FORMAT_VERSION. The header records both versions. Changing the spelling/layout of records or the projection requires a new notation version; supporting a future Graph IR format requires an explicit preservation review. The formatter adds no further JSON schema change beyond the breaking 0.5 format migration; default graph output remains JSON. The experimental View package’s source-aware Reading consumes original input and a matching explainSource result; graph-text output is not its input or an intermediate source representation. Its Map geometry and selection do not change Graph IR or source. LaTeX, decoders and theoretical adapters remain separately scoped.