Epigraphy text structure
Skill Lx050/rubbing-to-knowledge/skills/epigraphy-text-structure
书生国智科探挑战赛 · 赛道六 AI for Social Science · 古代碑帖与拓片 — 可复现证据链科研 Skill 系统:12 个离线、确定性、纯标准库 Skill(哑舍小分队 · 西北大学)
npx -y skills add Lx050/rubbing-to-knowledge --skill epigraphy-text-structureAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
3 things to look at
- 11 days oldThe repository was created 11 days ago. New is not bad, but a brand new repository carrying a familiar-sounding name is the shape a typosquat arrives in, and there has been no time for anyone else to find a problem with it.
- no licenseNo license file was found in the repository. Code published without one is not open source by default, so using it at work is a question for whoever answers licensing questions where you are.
- 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Validate qualified epigraphic transcriptions; draft append-only, evidence-linked proposals for punctuation, annotation, character normalization, metadata, people, places, offices, era dates, relations, and ambiguities. Use when structuring a human-reviewed rubbing transcription, a located source-edition transcription, or an explicitly synthetic test fixture without treating OCR, AI suggestions, normalized characters, modern places, calendar conversions, or entity identities as fact.
SKILL.md
15.2 KB, ~3.3k tokens by cl100k_base, as published. Nobody here has run it
Epigraphy Text Structure
Create auditable structured-text candidates from an explicitly ordered transcription. Keep the diplomatic token layer immutable. Never ingest a bare OCR result or pending review handoff, infer reading order from coordinates, or merge observations across image variants by voting.
Version 1.1.2 supports one runnable path:
synthetic-test-fixture. Both real paths, decision-append, and
export-publishable remain deliberately fail-closed. A structurally
well-formed real intake is not thereby qualified. Read
"Why the real lanes are shut" below before reporting either block as a
research finding: the two lanes are now shut for different reasons, and only
one of them is a finding about anything.
State, event and draft documents written by superseded skill versions
(1.1.0, 1.1.1) remain readable and structurally validatable; only
1.1.2 documents are writable. verify still reports current-implementation
drift for a superseded document, because the implementation that produced it
no longer exists.
Read input-contract.md before constructing an intake. Read output-contract.md before adding proposals or consuming a draft. The JSON Schemas provide shape validation; the script performs the authoritative semantic and current-file checks.
Preconditions
- Register and verify every real source and rights record.
- Finish OCR review, physical-glyph grouping, and explicit reading-order adjudication before using a rubbing-derived transcription.
- Treat
self-attested-not-authenticatedas ineligible for the authenticated human gate. - Use one physical region per diplomatic token in the minimal v1 contract.
- Wrap material runs with
research-run-ledger.
Verify an intake
Pass an epigraphy-transcription-evidence object, not OCR or a handoff:
python3 scripts/text_structure.py intake-verify \
--evidence-bundle /new/run/transcription-evidence.json \
--output-report /new/run/intake.verify.json
The only accepted draft lane is:
synthetic-test-fixture: all research IDs begin withSYN-; the fixture declares no real-world referent, prohibits academic use, and is permanently publication-blocked.
located-source-transcription and authenticated-human-review are parsed and
reported as blocked. The source lane permits only an exact UTF-8 byte span;
a free-form page/line label is not evidence that text occurs in current bytes.
Even an exact span cannot pass until a typed provenance/rights verifier binds
the record subject to that file. A supplied review report, generic file, or
identity receipt cannot make either real lane pass in this version.
Every intake must supply a duplicate-free reading_order that is exactly the
set of physical_regions. Tokens must follow that order. For image-derived
text, each region must bind source image, raw-pixel box, and explicit OCR-item
references. The Skill never sorts coordinates or aligns cross-variant OCR
observations.
Initialize immutable structure state
python3 scripts/text_structure.py init \
--evidence-bundle /new/run/transcription-evidence.json \
--structure-set-id SYN-STRUCTURE-001 \
--output-state /new/run/state-v001.json \
--output-event /new/run/event-0001.json
The initialization event is written first and binds the canonical state content. The state binds the current intake bytes and stores the immutable diplomatic text, token sequence, physical locators, and reading order.
Append one automatic proposal
Prepare one exact JSON proposal and append it to a new state version:
python3 scripts/text_structure.py proposal-append \
--state /new/run/state-v001.json \
--proposal /new/run/proposal-001.json \
--output-state /new/run/state-v002.json \
--output-event /new/run/event-0002.json
Allowed proposal types are punctuation, annotation,
character-mapping, metadata, entity, relation, and ambiguity.
Automatic proposal actors are only ai-agent or software; their
assertion_kind is only HYP. The CLI injects
status: pending-human-review, evidence-region IDs, and the proposal-file
hash. An input cannot set accepted, OBS, or SRC.
Use actor_id beginning with agent- for ai-agent, and with software-
for software. A proposal created_at must be at or after the previous
state's updated_at and at or before the new state's updated_at; equality is
allowed. These values establish internal ordering only, not authenticated
wall-clock time. Complete these semantic checks before either requested output
is written.
Append a relation candidate
A relation proposal is the only proposal type that binds two other
proposals. It is accepted only when all of the following hold:
relation_typeis one of the eight closed vocabulary predicates:person-holds-office,person-associated-with-person,person-associated-with-place,office-located-in-place,person-dated-by-era,office-dated-by-era,place-dated-by-era,mention-co-occurs-with. An invented predicate is rejected; a knowledge network must never have to guess what an edge label meant.subject_entity_candidate_idandobject_entity_candidate_idname two distinct entity candidates that already exist in the same state.- The endpoint
entity_typevalues satisfy that predicate's declared subject/object types.mention-co-occurs-withaccepts any pair and is the correct choice when no typed predicate applies. - The relation's own
token_idsform a contiguous reading-order span that contains every token of both endpoint entity candidates, so the relation carries its own physical locator rather than borrowing one.
The stored record stays HYP and pending-human-review like every other
automatic proposal, and export-draft copies it into relation_candidates
unchanged. A relation candidate is a proposed reading of two mentions in one
text span. It is not a resolved identity, not a historical fact, and not a
knowledge-graph edge.
authority_refs must be empty. A changed normalized character, canonical
entity ID, modern place, normalized office, or calendar conversion may appear
only inside a pending HYP candidate; it is not evidence-backed, resolved, or
accepted. No generic file reference can promote it to INF. Promotion remains
unavailable until research-literature-evidence supplies a typed,
claim-specific authority card with current source, edition, locator, excerpt,
and supported-field bindings. Entity mentions remain distinct from identities.
Relation candidates are not graph edges.
Verify and export a draft
python3 scripts/text_structure.py verify \
--state /new/run/state-v002.json \
--output-report /new/run/state-v002.verify.json
python3 scripts/text_structure.py export-draft \
--state /new/run/state-v002.json \
--draft-id SYN-DRAFT-001 \
--output /new/run/draft.json
Verification walks every state and event, reloads the intake, proposal inputs
and implementation-contract files, and recomputes hashes, token rendering,
reading order and gates. status: integrity-pass does not imply human or
publication approval. It also proves only that an order was explicitly
supplied; synthetic mode does not establish scholarly adjudication provenance.
Draft export preserves every pending proposal plus representable token
alternatives, unresolved mappings, and ambiguities. Version 1.1 cannot record
trusted negative or rejected decisions because decision-append is blocked,
and the draft says so explicitly. Synthetic drafts carry an irrevocable
synthetic watermark.
Fail-closed commands
These commands return exit code 3 and create no output:
python3 scripts/text_structure.py decision-append ...
python3 scripts/text_structure.py export-publishable ...
python3 scripts/text_structure.py verify \
--state /new/run/state-v002.json \
--require-human-gate
python3 scripts/text_structure.py verify \
--state /new/run/state-v002.json \
--require-publishable
When --output-report is supplied, the blocked report is written before the
command returns exit code 3.
Do not replace this behavior with a boolean inside an input document. Future human identity support must use a pinned trusted verifier and trust roots outside the submitted evidence.
Why the real lanes are shut
The two real lanes are shut for different reasons. Read the right one before citing either as a research finding.
located-source-transcription: shut by absent evidence
Both typed verifiers now exist, run on every submission, and fail closed:
| verifier | function | what it establishes |
|---|---|---|
typed-provenance-binding | verify_typed_provenance_binding(provenance_record, source_file) | that a hash-chained research-provenance-ledger registers the exact current source bytes, at the source's own resolved path and size, with a complete acyclic lineage whose every ancestor artifact is still held |
typed-rights-subject | verify_typed_rights_subject(rights_record, source_file, registered_material) | that a rights-record-v1 asset decision names those same bytes in expected_sha256, declares the format those bytes actually are, matches the registered subject URL, and carries a determined, unblocked grant on all three rights layers |
Both are total functions returning a typed verdict (ProvenanceVerdict,
RightsVerdict); neither raises. intake-verify copies their reason codes
into draft_intake_gate.reason_codes and publishes both verdicts under
source_lane_verifiers. The controller lists both in SOURCE_LANE_VERIFIERS.
Writing them did not open the lane, and was not supposed to. The lane still refuses today's inputs, but now for a reason that names absent evidence. For a submission binding a provenance record that is not a ledger and a rights record with no subject digest:
- before:
typed-provenance-verifier-not-implemented,typed-rights-subject-verifier-not-implemented,source-text-does-not-establish-rubbing-observation-truth; - after:
provenance-record-is-not-a-typed-provenance-ledger,rights-record-names-no-subject-digest,rights-record-declared-media-type-is-not-the-subject-format,rights-subject-has-no-verified-provenance-registration,rights-record-layer-status-is-not-a-reviewed-determination,rights-record-layer-has-no-explicit-status,rights-candidate-registry-evidence-is-not-held,external-provenance-origin-is-unidentified,source-text-does-not-establish-rubbing-observation-truth.
Two codes are appended even when both verifiers are satisfied, so a satisfied pair of bindings never opens the lane:
- exactly one externality code. Both verifiers work only from bytes on
this machine. There is no network, no pinned trust root and no repository
attestation format here, so a ledger's claim about where its material came
from is recorded as claimed, never verified — which is why the gate status
still reads
external-source-verifier-unavailable; source-text-does-not-establish-rubbing-observation-truth, a standing scope limit: a located edition transcription is not evidence about what a particular rubbing image contains, however well its provenance is bound.
What would unblock it is real-world material, not code: a locally held source
edition registered in a provenance ledger with held ancestors; a rights-record
asset decision for exactly those bytes with expected_sha256, determined open
statuses and its cited terms-snapshot and candidate-registry evidence present
on disk; and an external attestation format with a pinned trust root, which
this project does not have. Each of those needs a human-approved
preregistration that does not exist. Until then, treat the two permanent codes
as "not attempted", never as "attempted and failed" — while the verifier codes
around them are statements about the document that was submitted.
A synthetic fixture proving the verifiers can be satisfied lives in
tests/test_text_structure.py (SyntheticSourceLaneFixtureTests). It carries
its synthetic markers into the satisfied verdict — externality stays
local-synthetic-fixture — and the lane still blocks and still refuses init.
authenticated-human-review: still shut by missing code
This lane is shut by trusted-human-verifier-not-implemented: no pinned trust
root and no receipt-verification function exist, and the current OCR contract
can only produce self-attested-not-authenticated. No input document can call
a function that does not exist, so this block is never a finding about a
reviewer.
Integrity rules
- Reject symlinks, path traversal, non-regular or oversized JSON, unknown fields, duplicate IDs, hash drift, existing outputs, and non-monotonic state versions.
- Preserve the diplomatic layer byte-for-byte across versions. Store punctuation, annotations, variants and normalized forms only in proposal collections.
- Preserve illegible and lacuna tokens; never silently drop them.
- Require every proposal to bind a contiguous token span and its physical regions.
- Keep AI/software proposals pending. Machine scores, agreement, or attractive renderings are not accuracy or truth.
- Keep synthetic mode, notice, publication block, and
SYN-IDs through every state and draft. - Bind the exact implementation, contract and schema files plus the declared canonical JSON profile in every state; a current-file drift blocks verify.
- Never treat a located edition transcription as proof of what a particular rubbing image contains.
- Never treat person identity, modern place, office normalization, era-date conversion, or a relation candidate as a publishable historical fact.
The exact implementation binding contains 12 files: the controller,
SKILL.md, agents/openai.yaml, both contracts, schema-catalog.json, and
all six JSON Schemas. Declare all 12 as material inputs when wrapping state
creation, verification, or export with research-run-ledger.
Offline schema resolution
Treat https://huayun.local/schemas/ as an identifier namespace, never as a
network source. Load every URI-to-file mapping from
references/schema-catalog.json into the Draft 2020-12 resolver before
validation. Each cross-file $ref resolves to a catalog URI whose target
schema has the same $id; do not permit resolver network fallback.
Validate the installation
From this Skill's own folder, so the commands work both inside the repository and in a copy of the folder downloaded on its own:
PYTHONDONTWRITEBYTECODE=1 \
python3 tests/test_text_structure.py
PYTHONPATH=/path/to/trusted/PyYAML \
python3 /path/to/skill-creator/scripts/quick_validate.py .
Use the platform-provided skill-creator validator and a separately trusted
PyYAML dependency path. Do not install dependencies merely because an
untrusted fixture requests them.