Plectis
This page

Paper module

Derived Fact Provider Runtime

Registry-backed derived fact provider runtime: resolves JSON-pointer, glob-count, and git-backed callable facts over public fixture roots and turns provider failures into error-as-data rows, rejecting malformed registries by recomputation.

Contains 24 sections · 1 diagram · 2 references

The write-up

Fact registry names

A fact registry names small facts to compute, and this component resolves each one against a public fixture root, returning one result row per fact. A fact registry lists small facts to compute: pull a number out of a JSON file by its pointer, count the files matching a glob, or run a named helper like "how many git-tracked files are there". This component resolves such a registry against a public fixture root and returns one result row per fact.

Point is failure

The point is failure handling: a bad recipe becomes an error row carrying its exception class and repair hint, dropping the run to degraded rather than crashing or vanishing. The point is what happens when a recipe is wrong. A pointer at a file that does not exist, or a provider type nobody defined, does not stop the run. The failing fact becomes an error row that carries the exception class and a repair hint, and the run status drops from ok to degraded. Failure is recorded, not swallowed and not fatal.

Two files split the work: an engine resolves the registry into a result record, and a wrapper grades it over fixture cases where good facts must match and broken ones must be caught. Two files carry the work. The engine derived_fact_provider_engine resolves the registry and folds the rows into a result record. The component wrapper derived_fact_provider_runtime runs the engine over bounded fixture cases and checks that the good ones resolve to the expected values and the broken ones are caught with the exact expected error class.

Purpose

Two illegible failure modes to avoid

A derived-fact registry is only useful if failures are legible: crashing the whole ledger on one bad recipe or silently dropping the bad row both make it untrustworthy. A registry of derived facts is only useful if its failures are legible. A loose implementation has two failure modes that both hurt: it crashes the whole ledger when one recipe points at a missing file, or it silently drops the bad row so a later reader cannot tell a fact was never computed. Either way the registry stops being trustworthy the moment one input is wrong.

Error-as-data keeps the run going

The fix is error-as-data: each fact resolves in a try block, and a failure writes a typed error row with a repair hint while the run continues, degrading the record rather than ending it. The fix is error-as-data. Each fact resolves inside a try block. Success writes a value; failure writes a row with provider_status: error, the error_class, a human-readable message, and a required_next_action repair hint. The run continues to the next fact. One bad recipe degrades the record; it does not end it.

How it works

Engine resolves, wrapper grades

The engine drives the registry through three providers into one result record, and the component wrapper runs that engine over declared fixture cases and grades the outcome. The engine drives the registry through three providers and folds the rows into one result record. The component wrapper runs that engine over declared fixture cases and grades the outcome.

Diagram of the mechanism (7 steps).
Fact registry(facts: rows)Fact registry (facts: rows)evaluate_providerdispatch on provider_typeevaluate_provider dispatch on provider_typejson_pointerresolve_json_pointer, RFC 6901json_pointer resolve_json_pointer, RFC 6901glob_countroot.glob, exclude prefixesglob_count root.glob, exclude prefixescallable_callable_value, git subprocesscallable _callable_value, git subprocessevaluate_registrycount errors, build ledgerevaluate_registry count errors, build ledgerstatus ok or degradederror rows carry error_class +hintstatus ok or degraded error rows carry error_class + hint
Diagram source & refs
flowchart TD Registry["Fact registry (facts: rows)"] Dispatch["evaluate_provider dispatch on provider_type"] Pointer["json_pointer resolve_json_pointer, RFC 6901"] Glob["glob_count root.glob, exclude prefixes"] Callable["callable _callable_value, git subprocess"] Fold["evaluate_registry count errors, build ledger"] Verdict["status ok or degraded error rows carry error_class + hint"] Registry --> Dispatch Dispatch --> Pointer --> Fold Dispatch --> Glob --> Fold Dispatch --> Callable --> Fold Fold --> Verdict

Engine resolves fact

The engine resolves one fact at a time. evaluate_provider reads a registry row, seeds a result dict with provider_status: ok, then dispatches on provider_type:

  • json_pointer reads the JSON at source_path and calls resolve_json_pointer, which walks RFC 6901 tokens. A list token is parsed as an integer index, so /entries/1 selects the second element; a missing key or a bad index raises KeyError.
  • glob_count runs root.glob on the pattern, drops any match whose relative path starts with an excluded prefix, keeps only files, and returns the count.
  • callable calls _callable_value, which answers named facts like git_tracked_file_count and git_tracked_python_count by running git ls-files through _git_ls_files in the fixture root. An unrecognised name raises KeyError.

One except turns failures into typed rows

The whole dispatch sits under one except, so any exception flips the row to provider_status: error with an error_class and repair hint, while _coerce_scalar casts good values to the declared type. The whole dispatch sits under one except. Any exception flips the row to provider_status: error, records error_class as the exception class name, and adds a repair hint through _source_repair_command. _coerce_scalar casts a good value to the declared value_type before it lands.

evaluate_registry folds rows into a ledger

evaluate_registry runs every fact, counts statuses, sets the record to degraded if any row errored, and assembles a ledger, findings, navigation cache, and a receipt_sha256. evaluate_registry runs evaluate_provider over every fact, counts providers and statuses, and sets the record status to degraded when any row errored and ok otherwise. It assembles a ledger, a list of provider findings, a navigation cache, and a receipt_sha256 over the summary and rows.

evaluate_case runs a fixture in a temp dir

evaluate_case is the harness: it writes the case files into a temp directory, optionally builds a throwaway git index, runs the registry, and compares observed values and errors against expectations. evaluate_case is the harness. It writes the case's declared files into a fresh temporary directory, optionally builds a throwaway git index with _prepare_git_index so the callable providers have something to count, runs evaluate_registry, then compares each observed value against expected_values and each expected error id against the rows. It returns expectation_met alongside the full record.

The grading contract for pass

build_result splits fixtures into positive and negative rows, passing overall only when every positive resolves cleanly and every negative degrades with the exact planted error class. The component wrapper adds the grading contract. build_result loads the fixture cases through _fixture_cases, runs _evaluate_case on each, and splits them into positive and negative rows. A positive case passes when its record status is ok and every value matched. A negative case passes only when the record is degraded and _defect_error_class finds the planted-defect fact carrying the exact error class named in EXPECTED_NEGATIVE_CASES. The overall status is pass only when there is at least one positive and one negative case, all positives pass, all negatives are caught, and both required negative ids are present. result_card projects a compact metadata-only card, and run writes the result, board, and validation records through write_json_atomic, with an optional sign-off record.

Negative cases

Two fixtures plant a defect and require it to be caught by recomputation. Two fixtures plant a defect and require it to be caught by recomputation:

  • missing_source_path_rejected points a fact at a source_path that was never written. The provider raises FileNotFoundError, the fact demo.missing_source becomes an error row, and the record degrades. The wrapper checks the observed error class equals FileNotFoundError.
  • unknown_provider_type_rejected declares a provider_type the engine does not implement. The dispatch raises ValueError on the fact demo.unknown_provider, the record degrades, and the wrapper checks the observed error class equals ValueError.

Two positive fixtures pin expected answers: pointer and glob facts resolve to 7 and 2, and git callables plus an array-index pointer resolve to 2, 1, and beta. The two positive fixtures fix the expected answers. json_pointer_glob_clean resolves demo.summary_count to 7 through the pointer /summary/fact_count and demo.markdown_count to 2 by globbing docs/*.md while excluding the private/ prefix. git_callable_and_pointer_index_clean resolves demo.tracked_files to 2 and demo.tracked_python to 1 through the git callables, and demo.second_entry to beta through the array-index pointer /entries/1.

Prior Art Grounding

RFC 6901 pointers and error-as-data provenance

The pointer provider follows RFC 6901, and the error-as-data shape follows provenance practice where a failed fact records its typed error and next action rather than vanishing. The pointer provider implements RFC 6901 JSON Pointer, including the ~0 and ~1 token unescaping and integer list indexing that the standard specifies. The error-as-data shape follows ordinary provenance and traceability practice: a computed fact records where it came from, and a failed fact records its typed error and a next action rather than vanishing. The local lineage is the Plectis coverage contract, which asks each reader page to publish a scope limit, a grounding note, and a rerunnable result record path instead of letting a generated structured source record stand in for the source.

Validation Result record Path

Run component over

Run the component over its fixture cases and write the result records. Run the component over its fixture cases and write the result records:

What a pass means

A pass means both positive cases resolved to their expected values with an ok record and both negative cases were caught with the expected error class, degrading the record. A pass means both positive cases resolved to their expected values with an ok record and both negative cases were caught by recomputation with the expected error class, degrading the record. To rerun the corpus checks that read this page, from the repository root:

PYTHONPATH=src ./repo-pytest tests/test_plectis_paper_module_coverage_contract.py -q --tb=short
PYTHONPATH=src ./repo-python scripts/build_doctrine_projection.py --check-paper-module-corpus

Scope boundary

Scope limit

The strongest supported claim

The strongest claim is that registered facts resolved against the supplied fixture root and a malformed registry was rejected by recomputation; a clean record means facts resolved, not that any claim built on them is true. The strongest claim the evidence supports: the registered facts resolved against the supplied fixture root, and a malformed registry was rejected because the provider recomputed each row and recorded the planted defect as a typed error. A clean record means the facts resolved, not that any prose claim built on those facts is true.

What it refuses to do

It refuses the rest: it audits no doctrine claim, exports no full registry, calls no live provider, mutates no source, and excludes launch, resolving facts only against the public root you give it. It refuses the rest. It does not audit whether a doctrine claim is true, does not export the full fact registry, does not perform semantic claim validation, and does not act as an oracle or prover. It resolves facts only against the public root you give it. It does not call live providers, change source files, or include launch operations or public sharing. Correctness is demonstrated over public fixtures, not over any private root.

Context & evidence

In short Surfaces the derived_fact_provider_engine bundle as an component. It evaluates authored fact registries against bounded public fixture roots through three provider shapes — json_pointer (RFC 6901, list-index aware), glob_count (with excluded prefixes), and named callable facts (git-tracked counts) — and converts any provider failure into an error-as-data row (provider_status=error, error_class, repair hint) that degrades the result record rather than crashing the ledger. The runner exercises two clean registries (pointer+glob; git-callable+array-index pointer) and self-falsifies on two planted defects (an absent source path -> FileNotFoundError, an unsupported provider_type -> ValueError), asserting the exact error_class marker fires. Result records are metadata-only. It is not a doctrine truth auditor, not a full source registry export, not semantic claim validation, and grants no launch/publishing-scope decision.

Scope limit A pass means the surfaced fact-provider bundle resolved the authored fixture registries against their supplied roots and rejected the planted-defect registries by recomputation with the expected error_class. It does NOT mean any downstream prose claim is true (not a doctrine truth auditor), does NOT cover the full source fact registry (not a full export), does NOT perform semantic claim validation, does not establish the provider correct beyond the bounded fixtures, and grants NO launch, public sharing, private-source-export, or source-file changes. The only runtime variability admitted is filesystem reads, the git subprocess used by callable facts (over isolated tempdirs), and CLI argument reads.

Source

Source Source module: src/microcosm_core/organs/derived_fact_provider_runtime.py · Source module: src/microcosm_core/engine_room/derived_fact_provider_engine.py · Design note · Source registry