Skip to content

G0 (resumed): bootstrap the registry from code - #50

Merged
Hafeok merged 11 commits into
mainfrom
claude/registry-bootstrap-code-gl2erk
Aug 20, 2026
Merged

G0 (resumed): bootstrap the registry from code#50
Hafeok merged 11 commits into
mainfrom
claude/registry-bootstrap-code-gl2erk

Conversation

@Hafeok

@Hafeok Hafeok commented Aug 19, 2026

Copy link
Copy Markdown
Owner

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-lsp The declaration-level LSP subset, the two newly wired C# operations, and the capability probe
product-core/src/ground/ The extraction slice — pure, no LSP, no governance stack
ground-cli The ground binary: the corpus reader and the extract act
docs/g-track/ The session report

64 files, +8674. Nothing in prd-ground-as-ontology.md was edited — findings are reported and ride a later PR, as scoped.

Gates

cargo t 1454 passed / 0 failed · clippy clean · cargo xtask check 0 errors · ledger verify clean · ddd validate conformant, 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 high assurance, 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 documentSymbol output; 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's revisit_if is 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: definition is 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-backend was 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

claude added 11 commits August 18, 2026 13:29
…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
@Hafeok
Hafeok merged commit 5fd2481 into main Aug 20, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants