G0 (resumed): bootstrap the registry from code - #50
Merged
Conversation
…s it Wires the two operations the V5 entry probe found needed wiring only. `definition` reuses `normalize_locations` unchanged — the result is a `Location[]` shape that normaliser already accepted. `typeHierarchy` is three call sites (prepare, then supertypes/subtypes) and does need a new item normaliser: hierarchy items are not locations, and routing them through the location normaliser would keep uri+range while silently dropping the symbol identity, which is the half the subClassOf mapping row needs. The opaque `data` blob round-trips by construction: `HierarchyItem` keeps the server's item verbatim and hands that back, so an unknown field a future server adds survives too. Roslyn resolves the directional calls only from its own blob. The capability probe is the extractor-wide discipline: each of the six operations is called against a known declaration at start-up, and the call — never the advertised flag — is the verdict. Both divergence directions are named and reported. The over-advertising direction (flag true, result null) is the dangerous one: it reads as a gate passed with zero edges extracted, and downstream that absence would be read as divergence, fabricating ground from an instrument fault. The mock gained an over-advertise mode so that exact shape is a fixture rather than a paragraph. Host-layer change is additive: `initialize` now returns the server's capabilities instead of discarding them, and the client declares `definition` + `typeHierarchy` — correct practice, though measurement shows it changes nothing about what this server answers. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UAs9pz7qdr3t7LHbC1p1iA
It is scaffolding for the mock's own answers, not surface a caller depends on — the same narrowing the generator session applied to the registry slice. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UAs9pz7qdr3t7LHbC1p1iA
Fifty-nine events across six files. The narrowing came first: the mock's hierarchy responder is scaffolding for the mock's own answers, so it is crate-internal and never counted; what remains is the surface the extractor will actually depend on. Each verdict states what a caller learns and what the boundary cannot do — the probe cannot say why an operation is silent, the protocol layer cannot interpret a server's opaque blob, the mock proves wiring and never semantics. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UAs9pz7qdr3t7LHbC1p1iA
Rung zero, as ruled: deterministic LSP reads, per-language mapping rules, RDFS/OWL-RL entailment, CONSTRUCT rules to fixpoint, SHACL. No model anywhere in this path — extraction is constructively closed, so there is no candidate-generation step for one to do. The slice is `product-core/src/ground/`, pure and LSP-free: the reading half fills `CorpusFacts` and hands it over, which is what keeps the downstream-consumer contract intact. `ground-cli` is the adapter that drives the language host; it is where the ddd-lsp dependency lives. Three mechanics carried from the Oxigraph manifest are load-bearing and are asserted by fixtures. Rules are parsed once and cloned per round, so the fixpoint's wall-time measures execution rather than parsing. Every CONSTRUCT is drained before insert, because the triple iterator borrows the store. Registry Turtle comes from our own writer — fixed field order, sorted evidence, no blank nodes — never the oxigraph serialiser, which is not order-stable. Assertion identity is derived from the triple's own content, never from a position in a run. That settles Reading identity across rebuilds: the same corpus at the same ref proposes nothing the second time, a later ref proposes only what changed, and a disappeared symbol leaves a ratified file with no counterpart — §5.5's diff falls out of the file set with no run registry to keep in step. Every mapping row is gated on the capability probe. A row whose operation did not answer reports that by name; a row past the gate with nothing to read says it found nothing; the foreign-key row says it is not derivable from the declaration surface at all. Three different findings, three different lines, never one zero. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UAs9pz7qdr3t7LHbC1p1iA
A caller depends on plan/apply/render and the types they carry, never on how a row is spelled, how the fixpoint is driven, or how a file is rendered. The containment lookup in the facts went with it: the join is a CONSTRUCT rule now, so the Rust one was dead. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UAs9pz7qdr3t7LHbC1p1iA
Two hundred and fifty-three bindings across seventeen files, after the narrowing: the slice publishes plan, apply and render with the types they carry, and nothing about how a row is spelled or how the fixpoint is driven. Each verdict states what a caller learns and what the boundary cannot do. The reader cannot tell a domain type from infrastructure, see visibility, or recognise generated code — none of that is on the declaration surface, so all of it reaches the proposal and is reported rather than filtered. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UAs9pz7qdr3t7LHbC1p1iA
The properties row cannot tell implementation from domain structure — the declaration surface carries no visibility — so it proposes both and now *names* which came from a member the server reported as a field. That makes the group a reviewer would batch mechanically reportable instead of hand-counted, which is what the second-axis evidence needs. Nothing about member kind reaches an assertion file, so re-running over the same corpus proposes nothing and the working tree stays byte-clean — verified live, and the cleanest demonstration yet that content-derived identity is idempotent. Also splits three states the outcome line had collapsed: a dry run, a run with nothing new to propose, and a run that wrote files. Same discipline as the row outcomes; the report had been quietly failing it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UAs9pz7qdr3t7LHbC1p1iA
Five boundaries gained a sentence each: the reader reports a member kind and never a judgement, the properties row names what it cannot split, and the extract act says why nothing was written when nothing was. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UAs9pz7qdr3t7LHbC1p1iA
The pre-review report needs the exact lists, not a sample of six with "… 7 more" after it. `--json` emits the plan with its notes, which is how the two groups a reviewer would batch got counted: 18 assertions derived from generated migration code, 31 derived from members the server reported as fields. Both were hand-guessed first and both guesses were wrong. The notes were `#[serde(skip)]`; they are the reviewer's batching keys, so skipping them was the wrong default. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UAs9pz7qdr3t7LHbC1p1iA
Three boundaries: the plan publishes the batching keys, the properties row names the group it cannot split whole rather than sampled, and the extract act presents as text or as a query. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UAs9pz7qdr3t7LHbC1p1iA
… taught it Status line: G0 is not discharged. The pipeline holds end to end; two clauses of §11's single-source substitute gate remain open — the two merge acts, and one decision this session's scope did not cover. The report also records the §5.5 re-run, which was done twice. The first attempt used a ref two commits back and produced an empty diff — correct, because nothing inside the read subset had changed, and therefore a vacuous demonstration of a decay mechanism. Re-based on a ref with real churn it reports 22 candidates added and 3 symbols disappeared, the latter being a feature flag removed from a configuration type, checked independently against the corpus diff. The ranked finding is the second axis: derivation confidence is not domain relevance, and §5.2 conflates them into one column. Its forcing argument is recoverability — one rejected group can be found in the graph afterwards, the other cannot be found at all. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UAs9pz7qdr3t7LHbC1p1iA
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.
Session report:
docs/g-track/g0-session-report-2026-08-19.md.Status: G0 is not discharged. The pipeline is validated end to end — extraction, proposal, per-triple review and ratification hold. Two clauses of §11's single-source substitute gate remain open: the two merge acts on the instance, and the "should be identical" decision, which this session's scope did not cover.
What landed here
ddd-lspproduct-core/src/ground/ground-cligroundbinary: the corpus reader and the extract actdocs/g-track/64 files, +8674. Nothing in
prd-ground-as-ontology.mdwas edited — findings are reported and ride a later PR, as scoped.Gates
cargo t1454 passed / 0 failed · clippy clean ·cargo xtask check0 errors ·ledger verifyclean ·ddd validateconformant, 272 entries · contract-surface 331 events, 0 undischarged.The surface was narrowed before it was declared: the extraction slice publishes its acts — plan, apply, render — and nothing about how a row is spelled or how the fixpoint is driven. The narrowing also removed a containment lookup the CONSTRUCT rule had made dead.
The findings, ranked
1. The extraction table needs a second axis. §5.2's assurance column conflates derivation confidence (how reliably the instrument read the code) with domain relevance (whether the result is the kind of thing the registry is for). The corpus proved they are independent: 31 assertions at
highassurance, every mechanical check passing, the code read perfectly — and all 31 rejected. §5.2 says the declared rows are where extraction closes and review earns its keep on the inferred ones; that is now measured as wrong.The forcing argument is recoverability. One rejected group is findable in the graph afterwards through its evidence paths; the other is not findable at all, because nothing in a ratified assertion records that its property came from a field. A future reviewer cannot locate the class of error they would need to re-examine. That is ground that cannot be audited, and it makes marking derivation on the Reading non-optional.
2. Widening the declaration-level subset should be a filed decision with the closure consequence stated. Both remedies exist and both sit outside the subset — generated-code markers are not in
documentSymboloutput; visibility is already derived by the C# adapter's own facts layer. The subset was chosen to keep the extraction predicate closing, and it does close — on a predicate narrower than useful.3. The entailment stage is correct and idle. Subclass transitivity fired zero times across 17 edges: the hierarchy is flat. With a schema-only graph the stage's entire available yield is that closure, and this corpus has none. Recorded prominently so no later reader concludes the reasoner is doing work. Relatedly, the fixpoint's 13 ms is not a scale datum — the figure to watch against
g-dec-02'srevisit_ifis the 130 → 109 ratio.4. Per-triple review does not scale, and the answer is the same second axis arriving from the review side.
Plus:
definitionis wired and unspent (insurance, not waste); a correction to §5.2's under-advertising bullet, which cites a case the measurement does not support; and five smaller observations against the table.The §5.5 re-run, done twice
The first attempt used a ref two commits back and produced an empty diff — correct, because nothing inside the read subset had changed, and therefore a vacuous demonstration of a decay mechanism. Re-based on a ref with real churn it reports 22 candidates added and 3 symbols disappeared, the latter a feature flag removed from a configuration type, checked independently against the corpus diff. Both runs wrote nothing.
Corpus handling
corpus-backendwas read only — no commit, branch or file written to it, and the temporary worktree used for the baseline read was removed. Naming discipline holds on every line: corpus repositories are abstracted, domain identifiers are described structurally, and extracted triples live in the generated instance rather than here.Generated by Claude Code