feat(okf): den erklaerte bundle_id-en er identiteten - mountet er en filsystem-tilfeldighet
S7a-3 pkt. 1. Til i dag NEKTET reconcile_bundle_id en base som erklaerte en id katalogen ikke bar. Maalt mot K2 - den foerste leverte basen som erklaerer sin egen id (618 av 630 konseptfiler + rot-index, alle "k2-trinn1-20260903", levert som "K2-bundle-20260903") - betydde det at basen ikke kunne aapnes slik den var levert, og at eneste botemiddel var aa montere den paa nytt for haand, en gang per leveranse. PM-beslutning: konsumenten slakker. - Erklaert vinner (B1s rekkefoelge uroert), avviket REGISTRERES: ResolvedBundleId.mount + ProvenanceStamp.bundle_id_source + DryRunReport.bundle_id_source + run.bundle_id_notice (None ved enighet). Stempel-feltet er PAAKREVD uten default: None er en VERDI (veg-stien). - Det som fortsatt nekter er den EKTE kollisjonen: to KONSEPTER i en base som erklaerer ULIKE id-er (okf.assert_declared_ids_agree, kalt ved hver doer som aapner en base). Rot-index er IKKE med i enighets-settet - konsept-slaar-index er en presedens-regel, saa en index i utakt er fallbacken som taper. - KONSEKVENS, ikke scope-krype: explore._bundle_index loeser naa den erklaerte id-en. Den brukte Path(raw).name mens dispatcheren brukte reconcile...id; med erklaert-vinner ville explore() myntet approaches som navngir MOUNTET mens dispatcheren ruter paa ERKLAERINGEN - en utforskning med uruterbart mandat. Load-bearing MAALT: 10 mutasjoner alle roede mot HELE suiten, groenn kontroll 1243 passed / 5 skipped og golden demo-transcript.stdout byte-uendret (shasum -a 1 = ea8c534773acdbe41ae68f2c55724d69aaf8be4f). M1 1 / M2 1 / M3 1 / M4 9 / M5 2 / M6 1 / M7 1 / M8 2 / M9 2 / M11 1. Tre armer i test_bundle_id_reconciliation_loadbearing er SKREVET OM (ikke slettet) - de pinnet nekten beslutningen fjernet. (j) ble skarpere enn den den erstattet: erklaert id ruter, mountet nektes. Kontrakt: docs/okf-konsum-kontrakter.md § 3.1. Invariantrad i CLAUDE.md. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
5adb1cca62
commit
baae7507a9
14 changed files with 708 additions and 73 deletions
|
|
@ -224,6 +224,12 @@ class DryRunReport:
|
|||
#: because a dry run stops before any proposal exists, so there is no stamp to read it off —
|
||||
#: and this surface is precisely where the un-anchored case was measured to be silent.
|
||||
cost_baseline_anchored: bool
|
||||
#: Which knowledge base a real run would judge, and how its identity was established
|
||||
#: (``ProvenanceStamp.bundle_id_source``). Carried here for the same reason
|
||||
#: ``cost_baseline_anchored`` is: a dry run stops before any stamp exists, and this surface is
|
||||
#: precisely where a mount that disagrees with the declaration would otherwise be silent.
|
||||
#: ``None`` on the road path.
|
||||
bundle_id_source: okf.ResolvedBundleId | None
|
||||
#: Every cross-link the bundle navigation could not follow (``okf.Bundle.skipped``). EMPTY is a
|
||||
#: positive statement — "every cross-link was followed" — which is why it DEFAULTS, unlike
|
||||
#: ``cost_baseline_anchored`` above: a missing bool would have to claim something about an event
|
||||
|
|
@ -535,6 +541,34 @@ def cost_baseline_notice(anchored: bool) -> str | None:
|
|||
return None if anchored else _UNANCHORED_NOTICE
|
||||
|
||||
|
||||
def bundle_id_notice(resolved: okf.ResolvedBundleId | None) -> str | None:
|
||||
"""Render the one line that says a base was mounted under a name it does not answer to, or
|
||||
``None`` when there is nothing to say.
|
||||
|
||||
The warning half of the S7a-3 slacken. A declared id that disagrees with its directory is no
|
||||
longer refused — it is a filesystem accident, and refusing it made the first delivered corpus
|
||||
that declares its own id unopenable — but it must not become SILENT either: every artefact the
|
||||
run stamps names the declared id, while the operator typed the mount.
|
||||
|
||||
ONE renderer with N callsites, never N copies of the wording (kø-(p)), and it takes the
|
||||
ALREADY-RESOLVED value rather than a bundle path: a renderer that re-read the base would be a
|
||||
second resolution of the same rule, free to drift from the run it describes
|
||||
(``cost_baseline_notice``'s rule, and the reason ``ResolvedBundleId`` carries the mount).
|
||||
|
||||
``None`` on agreement AND on ``None`` — omission, never an empty row (``mandate.announce``'s
|
||||
rule). A run with no knowledge base has no identity to disagree about.
|
||||
|
||||
Both names are printed. A warning that says only "mismatch" leaves the operator to go and look
|
||||
for the two values it is warning about."""
|
||||
if resolved is None or resolved.id == resolved.mount:
|
||||
return None
|
||||
return (
|
||||
f" Knowledge base: declares bundle_id {resolved.id!r} (source: {resolved.origin}) but is "
|
||||
f"mounted as {resolved.mount!r} — the DECLARED id is the identity, so every artefact this "
|
||||
f"run stamps names {resolved.id!r}"
|
||||
)
|
||||
|
||||
|
||||
def collision_notice(collisions: tuple[VerdictCollision, ...]) -> str | None:
|
||||
"""Render which candidates two bases both described, or ``None`` when none did.
|
||||
|
||||
|
|
@ -690,11 +724,13 @@ async def run_project(
|
|||
# before the amendment (every commons-owned golden) is legitimately un-anchored -> None =
|
||||
# pre-S4.0 behaviour. A baseline that exists but is malformed still raises (fail-closed).
|
||||
if bundle_dir is not None:
|
||||
# ONE bundle-id rule (Step 10): the base is reconciled against the mount it was opened
|
||||
# from, HERE rather than in ``explore._bundle_index``, which stays pure and does no I/O.
|
||||
# A base that declares an id its mount does not carry is refused before anything is spent.
|
||||
okf.reconcile_bundle_id(bundle_dir)
|
||||
bundle = okf.navigate_bundle(bundle_dir)
|
||||
# ONE bundle-id rule (Step 10, slackened S7a-3 pkt. 1): the DECLARED id is the identity and
|
||||
# the mount is carried alongside, so a base delivered under a directory name of its own is
|
||||
# opened rather than refused. What is still refused, before a single model call: a base
|
||||
# whose concepts declare two different corpora.
|
||||
resolved_bundle_id: okf.ResolvedBundleId | None = okf.reconcile_bundle_id(bundle_dir)
|
||||
okf.assert_declared_ids_agree(bundle)
|
||||
project = _project_from_bundle(bundle_dir, project_id, bundle=bundle)
|
||||
# The THIRD projection into ``CostBaseline`` (MAJOR-4), behind an EXPLICIT commission and
|
||||
# never silent. The refusal PROPAGATES rather than degrading to the file loader: a caller
|
||||
|
|
@ -722,6 +758,8 @@ async def run_project(
|
|||
citations = [chunk_dict_to_citation(c) for c in chunks]
|
||||
context = "\n".join(c["snippet"] for c in chunks)
|
||||
skipped_links = ()
|
||||
# No knowledge base, so no bundle identity — said by ABSENCE rather than by minting one.
|
||||
resolved_bundle_id = None
|
||||
debate_tools = [make_retrieval_tool(docs_dir, top_k=top_k)]
|
||||
|
||||
# Trekk B2 (krav 3): configured MCP servers become tools the AGENTS can call during the debate.
|
||||
|
|
@ -783,6 +821,7 @@ async def run_project(
|
|||
max_tokens=max_tokens,
|
||||
top_k=top_k,
|
||||
cost_baseline_anchored=baseline is not None,
|
||||
bundle_id_source=resolved_bundle_id,
|
||||
skipped_links=skipped_links,
|
||||
)
|
||||
# The MCP lifecycle (Trekk B2): entered HERE, after the dry-run cut above, so a dry run never
|
||||
|
|
@ -914,6 +953,10 @@ async def run_project(
|
|||
# anchoring than the one that ran. The road path is anchored by construction (the reference
|
||||
# project's own cost_items ARE the baseline); a bundle is anchored iff it ships the file.
|
||||
cost_baseline_anchored=baseline is not None,
|
||||
# WHICH corpus was judged, and whether the base named itself or the mount named it for it.
|
||||
# Read off the SAME resolution the run opened the base with (kø-(p)); ``None`` on the road
|
||||
# path, where no knowledge base exists to name.
|
||||
bundle_id_source=resolved_bundle_id,
|
||||
# B4: which external service the debate actually called. Read AFTER the debate, so it is a
|
||||
# record rather than an intention. The honesty limit lives on ``ExternalCall`` itself: this
|
||||
# is the call and its source, not a verified rendering of the service's answer.
|
||||
|
|
@ -2842,6 +2885,12 @@ def main(argv: list[str] | None = None) -> int:
|
|||
nav_notice = skipped_links_notice(report.skipped_links)
|
||||
if nav_notice is not None:
|
||||
print(nav_notice)
|
||||
# The third silence on this surface (S7a-3 pkt. 1): a base delivered under a directory name
|
||||
# of its own now OPENS, so the disagreement has to be said out loud or nothing ever reports
|
||||
# that the run's artefacts name something other than the path the operator typed.
|
||||
id_notice = bundle_id_notice(report.bundle_id_source)
|
||||
if id_notice is not None:
|
||||
print(id_notice)
|
||||
return 0
|
||||
|
||||
try:
|
||||
|
|
@ -2890,6 +2939,11 @@ def main(argv: list[str] | None = None) -> int:
|
|||
nav_notice = skipped_links_notice(result.skipped_links)
|
||||
if nav_notice is not None:
|
||||
print(nav_notice)
|
||||
# Same renderer on the full run, read off the run's OWN stamp — so stdout and the outbox
|
||||
# artefact cannot disagree about which corpus was judged.
|
||||
id_notice = bundle_id_notice(result.provenance.bundle_id_source)
|
||||
if id_notice is not None:
|
||||
print(id_notice)
|
||||
# The settlement against the commission (Trekk A4). Empty without a mandate, so an
|
||||
# un-commissioned run prints exactly what it printed before.
|
||||
settlement = settle(result.coverage)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue