Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -272,3 +272,20 @@ jobs:
${{ runner.temp }}/caboodle-phase2/anticipated-question.log
${{ runner.temp }}/caboodle-phase2/empty-question.log
${{ runner.temp }}/caboodle-phase2/*.log

repository-pendant-source:
name: Repository pendant source controls
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.12'
- name: Install pinned RDF test parser
run: python3 -m pip install rdflib==7.6.0
- name: Test copied pointer and publication boundaries
run: |
python3 scripts/test-repository-share-query.py
python3 scripts/test-repository-knowledge.py
python3 scripts/test-repository-share-publication.py
19 changes: 19 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -194,3 +194,22 @@ jobs:
done
echo 'Registry visibility is UNKNOWN; publication is not accepted.' >&2
exit 1

repository-pendant:
name: Verify repository pendant
needs: [release-please, publish]
if: always() && needs.publish.result == 'success'
runs-on: ubuntu-latest
timeout-minutes: 45
permissions:
contents: read
env:
RELEASE_TAG: ${{ startsWith(github.ref, 'refs/tags/') && github.ref_name || needs.release-please.outputs.tag_name }}
GH_TOKEN: ${{ github.token }}
steps:
- uses: actions/checkout@v4
with:
ref: ${{ env.RELEASE_TAG }}
fetch-depth: 0
- name: Verify the bounded public pointer corpus
run: python3 scripts/verify-repository-share.py "$RELEASE_TAG" "$(git rev-parse HEAD)"
8 changes: 8 additions & 0 deletions docs/knowledge/alignment-status.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"status": "no-approved-mappings",
"approved_record_count": 0,
"carrier_sha256": "f74d895765cf2975b23c6a095b3c09a992865950f9199a7e53f9d2042679db10",
"scope": "scbrown/tambo repository pendant source",
"basis": "No verified approved artifact or pairs supplied at source review; empty carrier is explicit. This is not a global absence claim.",
"curation_contract": "https://github.com/scbrown/quipu/blob/main/docs/design/cross-graph-alignment.md"
}
6 changes: 6 additions & 0 deletions docs/knowledge/alignments.ttl
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# SSSOM/RDF carrier: explicitly no approved Chaski cross-stack mappings.
# This is an empty mapping graph, not an absent/corrupt input or a claim that
# no mappings exist anywhere. Candidate records require the existing curator
# path before publication as accepted mappings. Dependencies remain dependencies.
@prefix sssom: <https://w3id.org/sssom/> .
@prefix owl: <http://www.w3.org/2002/07/owl#> .
102 changes: 102 additions & 0 deletions docs/knowledge/repository-knowledge.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
{
"source_revision": "ccdfa3a2ed8747228b486f6ee97f4c291aadac26",
"reviewed_at": "2026-10-21T06:26:04.583642Z",
"max_age_seconds": 2592000,
"records": [
{
"kind": "idea",
"source": "README.md",
"subject": "http://aegis.gastown.local/ontology/doc/tambo/README.md",
"summary": "Tambo installs and verifies the knowledge-tool stack from a reviewable plan. The transition retains the caboodle command and existing plan/state paths; publication and installed verification remain separate.",
"source_sha256": "8bb36e408f903090f2f78a481dcb3a2214b45feea2071a6a77285a0168d6b19c",
"type": "Concept"
},
{
"kind": "idea",
"source": "docs/book/src/architecture.md",
"subject": "http://aegis.gastown.local/ontology/doc/tambo/docs%2Fbook%2Fsrc%2Farchitecture.md",
"summary": "The architecture separates plan, apply and verify. Guided intended-use answers become reviewable plan data and executable reader-path contracts rather than implicit permission to install.",
"source_sha256": "21fb4ce1e2827a14a6550a5154c7b9f15e92435dd265721ab4d4ed6f819ba97e",
"type": "Concept"
},
{
"kind": "interface",
"source": "src/main.rs",
"subject": "http://aegis.gastown.local/ontology/code/tambo/src%2Fmain.rs",
"summary": "The Clap command tree defines quickstart, plan, apply, verify and doctor, with explicit plan/state paths and opt-in remote credential provisioning.",
"source_sha256": "1062af6157fec196ffe42ea259c8714573bcdb0964e00d1ab9b96e40abb1c1da",
"properties": {
"interfaceKind": "CLI",
"publicName": "tambo and compatible caboodle command tree"
}
},
{
"kind": "interface",
"source": "src/model.rs",
"subject": "http://aegis.gastown.local/ontology/code/tambo/src%2Fmodel.rs",
"summary": "The serialized Plan schema defines profiles, ordered tools, optional shares and destination database, intended-use contracts and host exclusions. Unknown plan fields are rejected.",
"source_sha256": "8cde1e7890d525cb5f38f8ff5bebccb69a0489699435dc68d6a843618f9f8932",
"properties": {
"interfaceKind": "file-format",
"publicName": "caboodle-plan.toml Plan and JSON State"
}
},
{
"kind": "interface",
"source": "src/adapter.rs",
"subject": "http://aegis.gastown.local/ontology/code/tambo/src%2Fadapter.rs",
"summary": "The Adapter trait separates desired version, installation, version read-back and functional verification. Built-in adapters integrate the selected stack tools; package adapters may bind verification to PATH executables.",
"source_sha256": "7ff5434afe2a2fbcdaf600341127447316498c6f211ff804621e9f6f77b9b343",
"properties": {
"interfaceKind": "library",
"publicName": "caboodle::adapter::Adapter"
},
"depends_on": [
"http://aegis.gastown.local/ontology/repo_quipu"
]
},
{
"kind": "decision",
"source": "Cargo.toml",
"subject": "http://aegis.gastown.local/ontology/code/tambo/Cargo.toml",
"summary": "The package and primary command are tambo, while the Rust library import name remains caboodle and a legacy caboodle binary is explicitly declared for compatibility.",
"source_sha256": "7e31dcd35cb941031963d783120fc1653cf113914b5b0fe473760c08b898f752",
"type": "DecisionRecord",
"properties": {
"status": "active",
"supersessionStatus": "not-recorded-in-source"
}
},
{
"kind": "start-here",
"source": "README.md",
"subject": "http://aegis.gastown.local/ontology/doc/tambo/README.md",
"summary": "Start with the local single-user quickstart and its verified-tool success checks before selecting remote service mode.",
"source_sha256": "8bb36e408f903090f2f78a481dcb3a2214b45feea2071a6a77285a0168d6b19c",
"properties": {
"startHereOrder": 1,
"glossaryTerm": "https://scbrown.github.io/quechua/ns#Tool"
}
},
{
"kind": "start-here",
"source": "docs/book/src/configuration.md",
"subject": "http://aegis.gastown.local/ontology/doc/tambo/docs%2Fbook%2Fsrc%2Fconfiguration.md",
"summary": "Read the TOML plan, JSON progress state and explicit remote credential boundaries before changing installation targets or endpoint configuration.",
"source_sha256": "45754e285dd180793bc1c1daf866d5d8455512d96aa4dbec4050e90cc8115fda",
"properties": {
"startHereOrder": 2
}
},
{
"kind": "start-here",
"source": "Cargo.toml",
"subject": "http://aegis.gastown.local/ontology/code/tambo/Cargo.toml",
"summary": "Read the declared library and binary names before integrating the crate or changing compatibility assumptions.",
"source_sha256": "7e31dcd35cb941031963d783120fc1653cf113914b5b0fe473760c08b898f752",
"properties": {
"startHereOrder": 3
}
}
]
}
53 changes: 53 additions & 0 deletions docs/knowledge/repository-knowledge.shapes.ttl
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
@prefix a: <http://aegis.gastown.local/ontology/> .
@prefix sh: <http://www.w3.org/ns/shacl#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
@prefix sssom: <https://w3id.org/sssom/> .
@prefix owl: <http://www.w3.org/2002/07/owl#> .
@prefix prov: <http://www.w3.org/ns/prov#> .

# This profile constrains only explicitly curated repository knowledge. It
# does not turn every imported Concept or CodeModule into a Bobbin record.
a:TamboKnowledgeProfile a sh:NodeShape ;
sh:targetSubjectsOf a:knowledgeKind ;
sh:property [ sh:path rdfs:label ; sh:minCount 1 ; ] ;
sh:property [ sh:path rdfs:comment ; sh:minCount 1 ; sh:datatype xsd:string ; ] ;
sh:property [ sh:path a:knowledgeKind ; sh:minCount 1 ;
sh:in ( "idea" "interface" "decision" "start-here" ) ; ] ;
sh:property [ sh:path a:filePath ; sh:minCount 1 ; sh:datatype xsd:string ; ] ;
sh:property [ sh:path a:reviewAfter ; sh:minCount 1 ; sh:maxCount 1 ; sh:datatype xsd:dateTime ; ] ;
sh:property [ sh:path a:glossaryTerm ; sh:nodeKind sh:IRI ; ] ;
sh:property [ sh:path a:sourceHash ; sh:minCount 1 ; sh:maxCount 1 ; sh:pattern "^[0-9a-f]{64}$" ; ] ;
# maxAge is seconds since the explicit source review, not an eviction rule.
sh:property [ sh:path a:maxAge ; sh:minCount 1 ; sh:maxCount 1 ; sh:datatype xsd:integer ; sh:minExclusive 0 ; ] ;
sh:property [ sh:path prov:wasDerivedFrom ; sh:minCount 1 ; sh:nodeKind sh:IRI ; ] .

a:TamboInterfaceProfile a sh:NodeShape ;
sh:targetSubjectsOf a:interfaceKind ;
sh:property [ sh:path rdfs:label ; sh:minCount 1 ; ] ;
sh:property [ sh:path a:interfaceKind ; sh:minCount 1 ; sh:maxCount 1 ;
sh:in ( "CLI" "MCP" "REST" "config" "file-format" "library" ) ; ] ;
sh:property [ sh:path a:publicName ; sh:minCount 1 ; sh:datatype xsd:string ; ] ;
sh:property [ sh:path a:depends_on ; sh:nodeKind sh:IRI ; ] .

a:TamboDecisionProfile a sh:NodeShape ;
sh:targetSubjectsOf a:supersessionStatus ;
sh:property [ sh:path rdfs:label ; sh:minCount 1 ; ] ;
sh:property [ sh:path a:status ; sh:minCount 1 ; sh:maxCount 1 ; sh:in ( "active" "superseded" "proposed" ) ; ] ;
sh:property [ sh:path a:supersessionStatus ; sh:minCount 1 ; sh:maxCount 1 ;
sh:in ( "not-recorded-in-source" "recorded" ) ; ] .

# Existing SSSOM/RDF is a record, not a second identity-assertion format. The
# native align decide/apply path remains the only way to derive identity knots.
a:TamboMappingRecordProfile a sh:NodeShape ;
sh:targetSubjectsOf sssom:subject_id ;
sh:property [ sh:path rdfs:label ; sh:minCount 1 ; ] ;
sh:property [ sh:path sssom:subject_id ; sh:minCount 1 ; sh:maxCount 1 ; sh:nodeKind sh:IRI ; ] ;
sh:property [ sh:path sssom:object_id ; sh:minCount 1 ; sh:maxCount 1 ; sh:nodeKind sh:IRI ; ] ;
sh:property [ sh:path sssom:predicate_id ; sh:minCount 1 ; sh:maxCount 1 ; sh:nodeKind sh:IRI ; ] ;
sh:property [ sh:path sssom:mapping_justification ; sh:minCount 1 ; sh:maxCount 1 ; sh:nodeKind sh:IRI ; ] .

a:TamboNoHandAuthoredIdentity a sh:NodeShape ;
sh:targetSubjectsOf owl:sameAs ;
sh:property [ sh:path rdfs:label ; sh:minCount 1 ; ] ;
sh:property [ sh:path owl:sameAs ; sh:maxCount 0 ; ] .
32 changes: 32 additions & 0 deletions docs/knowledge/stored-queries.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
[
{
"name": "repository_ideas",
"description": "Repository-owned repository ideas",
"template": "PREFIX a: <http://aegis.gastown.local/ontology/> PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#> SELECT * WHERE { ?s a a:Concept; rdfs:comment ?summary . FILTER(STRSTARTS(STR(?s), \"http://aegis.gastown.local/ontology/doc/tambo/\") || STRSTARTS(STR(?s), \"http://aegis.gastown.local/ontology/code/tambo/\")) } ORDER BY ?s LIMIT 100",
"params": []
},
{
"name": "repository_interfaces",
"description": "Repository-owned repository interfaces",
"template": "PREFIX a: <http://aegis.gastown.local/ontology/> PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#> SELECT * WHERE { ?s a:interfaceKind ?kind; a:publicName ?name . FILTER(STRSTARTS(STR(?s), \"http://aegis.gastown.local/ontology/doc/tambo/\") || STRSTARTS(STR(?s), \"http://aegis.gastown.local/ontology/code/tambo/\")) } ORDER BY ?s LIMIT 100",
"params": []
},
{
"name": "repository_decisions",
"description": "Repository-owned repository decisions",
"template": "PREFIX a: <http://aegis.gastown.local/ontology/> PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#> SELECT * WHERE { ?s a a:DecisionRecord; a:status ?status . OPTIONAL { ?s <http://purl.org/dc/terms/isReplacedBy> ?successor } FILTER(STRSTARTS(STR(?s), \"http://aegis.gastown.local/ontology/doc/tambo/\") || STRSTARTS(STR(?s), \"http://aegis.gastown.local/ontology/code/tambo/\")) } ORDER BY ?s LIMIT 100",
"params": []
},
{
"name": "repository_start_here",
"description": "Repository-owned repository start here",
"template": "PREFIX a: <http://aegis.gastown.local/ontology/> PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#> SELECT * WHERE { ?s a:startHereOrder ?order . FILTER(STRSTARTS(STR(?s), \"http://aegis.gastown.local/ontology/doc/tambo/\") || STRSTARTS(STR(?s), \"http://aegis.gastown.local/ontology/code/tambo/\")) } ORDER BY ?s LIMIT 100",
"params": []
},
{
"name": "repository_freshness",
"description": "Repository-owned repository freshness",
"template": "PREFIX a: <http://aegis.gastown.local/ontology/> PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#> SELECT * WHERE { ?s a:reviewAfter ?reviewAfter; a:maxAge ?maxAgeSeconds . FILTER(STRSTARTS(STR(?s), \"http://aegis.gastown.local/ontology/doc/tambo/\") || STRSTARTS(STR(?s), \"http://aegis.gastown.local/ontology/code/tambo/\")) } ORDER BY ?s LIMIT 100",
"params": []
}
]
76 changes: 76 additions & 0 deletions queries/repository-share-tambo.rq
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
PREFIX aegis: <http://aegis.gastown.local/ontology/>
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX prov: <http://www.w3.org/ns/prov#>
PREFIX dct: <http://purl.org/dc/terms/>
PREFIX sssom: <https://w3id.org/sssom/>
PREFIX owl: <http://www.w3.org/2002/07/owl#>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>

# Public repository knowledge only. Bobbin publishes its replaceable snapshot
# into ROOT, so graph/group selectors cannot see it. Keep this predicate list
# aligned with Bobbin's generate_chunk_turtle output: selecting every outgoing
# edge also pulls private operational literals into a public release artifact.
CONSTRUCT { ?s ?p ?o }
WHERE {
{
?s ?p ?o .
FILTER(
STRSTARTS(STR(?s), "http://aegis.gastown.local/ontology/code/tambo/") ||
STRSTARTS(STR(?s), "http://aegis.gastown.local/ontology/chunk/tambo/") ||
STRSTARTS(STR(?s), "http://aegis.gastown.local/ontology/doc/tambo/")
)
VALUES ?p {
rdf:type rdfs:label
aegis:filePath aegis:repo aegis:language
aegis:inDocument aegis:chunkOrder aegis:nextChunk aegis:mentions
aegis:name aegis:definedIn aegis:symbolKind
aegis:heading aegis:headingDepth
rdfs:comment rdfs:seeAlso prov:wasDerivedFrom dct:modified dct:isReplacedBy
aegis:knowledgeKind aegis:interfaceKind aegis:publicName aegis:status
aegis:supersessionStatus aegis:startHereOrder aegis:glossaryTerm
aegis:reviewAfter aegis:maxAge aegis:depends_on aegis:sourceHash
}
# Bobbin emits weak mention names as strings. Quipu may additionally
# resolve those names to IRIs under the same predicate in its local store;
# those derived edges do not satisfy the shipped string-valued shape.
FILTER(?p != aegis:mentions || isLiteral(?o))
}
UNION
{
?s ?p ?o .
{ ?s a sssom:MappingSet } UNION { ?s a owl:Axiom }
VALUES ?p {
rdf:type rdfs:label prov:wasDerivedFrom
sssom:mappings sssom:subject_id sssom:object_id sssom:predicate_id
sssom:subject_label sssom:object_label sssom:mapping_justification
sssom:predicate_modifier sssom:confidence sssom:author_id
}
}
UNION
{
VALUES ?s {
aegis:repo_caboodle
aegis:repo-embedded-knowledge-databases-directive-2026-09-03
}
?s ?p ?o .
}
# Versioned crew memory is internal source, including references attached to
# otherwise public context nodes. Internal backups use a separate explicit scope.
FILTER(!STRSTARTS(STR(?s), "urn:quipu:memory:"))
FILTER(!STRSTARTS(STR(?p), "https://quipu.dev/memory#"))
FILTER(!STRSTARTS(STR(?o), "urn:quipu:memory:"))
# Work tracking identifiers are not public repository knowledge. Filter
# both endpoints and literal mentions instead of renaming entity identity.
FILTER(!REGEX(STR(?s), "(^|[^A-Za-z0-9_])aegis-[A-Za-z0-9]"))
FILTER(!REGEX(STR(?o), "(^|[^A-Za-z0-9_])aegis-[A-Za-z0-9]"))
# Exclude the whole node when a required label contains an internal ID.
# Dropping only its label would leave a typed, SHACL-invalid fragment.
MINUS {
?s ?internalPredicate ?internalValue .
FILTER(REGEX(STR(?internalValue), "(^|[^A-Za-z0-9_])aegis-[A-Za-z0-9]"))
}
MINUS {
?o ?targetPredicate ?targetValue .
FILTER(REGEX(STR(?targetValue), "(^|[^A-Za-z0-9_])aegis-[A-Za-z0-9]"))
}
}
Loading
Loading