From 53fdff6fc7d5a7ca1559c96178b893ae939148b5 Mon Sep 17 00:00:00 2001 From: Erin Spencer Date: Fri, 11 Sep 2026 23:37:59 -0700 Subject: [PATCH 01/15] fix(stack): reconcile English Gonol authority in work graph --- stack-manifest.json | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/stack-manifest.json b/stack-manifest.json index fe4bb69..58693da 100644 --- a/stack-manifest.json +++ b/stack-manifest.json @@ -1,7 +1,7 @@ { "schema": "the-interdependency.stack-manifest", "version": "1.1.0", - "work_graph_sha256": "bbcb6b7582192c02e79f5b98b8f857385a07cda3280f24602f825ecd15ac405f", + "work_graph_sha256": "aa979936a351d2331cf8079939bba5ecb0bc9d694a29badd17335dad6afb2086", "repositories": [ { "repository": "The-Interdependency/skill-lib", @@ -24,8 +24,8 @@ { "repository": "The-Interdependency/edcm", "commit": "7951ca32ba0f2494dc68ff9b7f6a80151918a56d", - "authority": "measurement and text-gonol construction", - "relation": "pinned canonical repository view at libs/edcm/; stack-local work at research/edcm/" + "authority": "measurement and evaluation of text-domain outputs", + "relation": "pinned canonical repository view at libs/edcm/; stack-local measurement research at research/edcm/; English Gonol construction is separate at research/english-gonol/" }, { "repository": "The-Interdependency/pcea", @@ -121,6 +121,15 @@ "relation": "adjacent internal research; no external physics transfer", "canonical_release": false, "authority_transfer": false + }, + { + "workspace": "research/english-gonol/", + "participant_id": "english-gonol", + "repository": "The-Interdependency/stack", + "commit": "030022948fb7c749961ae65743a4448c4bb6cbbe", + "relation": "stack-local English lexical/gonol construction separated from EDCM; consumes UCNS geometry; EDCM may evaluate outputs but does not define construction", + "canonical_release": false, + "authority_transfer": false } ] } From 78ea3a3730b35f8c7872e40b5f14bc1083fbf75c Mon Sep 17 00:00:00 2001 From: Erin Spencer Date: Fri, 11 Sep 2026 23:38:35 -0700 Subject: [PATCH 02/15] fix(stack): align human manifest with English Gonol separation --- STACK_MANIFEST.md | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/STACK_MANIFEST.md b/STACK_MANIFEST.md index 4415d84..f09445f 100644 --- a/STACK_MANIFEST.md +++ b/STACK_MANIFEST.md @@ -6,9 +6,10 @@ Provenance and authority-boundary record for `The-Interdependency/stack`. - Layout migration UTC: `2026-08-30T02:58:49Z` - PCEA canonical refresh UTC: `2026-08-31T07:49:28Z` at `91ffa8c7249dfb810ca64a0bbc500481c0bd12a9` - EPAC extraction reconciliation UTC: `2026-09-05` at `d8868858b2e455381ce670797bdbe47189bdc496` +- English Gonol separation reconciliation UTC: `2026-09-12` at `030022948fb7c749961ae65743a4448c4bb6cbbe` - Stack-manifest schema: `the-interdependency.stack-manifest` version `1.1.0` - Work-graph digest (SHA-256 over canonical `repositories` + `research_participants` + `boundaries` JSON): - `bbcb6b7582192c02e79f5b98b8f857385a07cda3280f24602f825ecd15ac405f` + `aa979936a351d2331cf8079939bba5ecb0bc9d694a29badd17335dad6afb2086` - Machine-readable copy: [`stack-manifest.json`](stack-manifest.json) ## Directory contract @@ -33,7 +34,7 @@ meaning used by that repository. | `The-Interdependency/skill-lib` | `fb3b53a7629f7f03ecf255167d52c13abef1a979` | main | organization-wide build and evidence doctrine | operational snapshot at `skill-lib/` | | `The-Interdependency/metapat` | `34d954aa1e2092e615b03a180500f6b6977f501e` | main | semantic authority (Meta Energy Theory) | canon view `libs/metapat/`; research `research/metapat/` | | `The-Interdependency/ucns` | `828c0b8bbcfc267efb5701da714191c1f73a81ff` | main | geometry and mathematical representation | canon view `libs/ucns/`; research `research/ucns/` | -| `The-Interdependency/edcm` | `7951ca32ba0f2494dc68ff9b7f6a80151918a56d` | main | measurement and text-gonol construction | canon view `libs/edcm/`; research `research/edcm/` | +| `The-Interdependency/edcm` | `7951ca32ba0f2494dc68ff9b7f6a80151918a56d` | main | measurement and evaluation of text-domain outputs | canon view `libs/edcm/`; measurement research `research/edcm/`; English Gonol construction is separate at `research/english-gonol/` | | `The-Interdependency/pcea` | `91ffa8c7249dfb810ca64a0bbc500481c0bd12a9` | main | prime circle encryption algorithm | canon view `libs/pcea/`; research `research/pcea/` | | `The-Interdependency/ptcna` | `97abdd1bbda61a68e0aac8595a32a3cb0ce73487` | main | prime tensor circled neural architecture | canon view `libs/ptcna/`; research `research/ptcna/` | | `The-Interdependency/epac` | `d8868858b2e455381ce670797bdbe47189bdc496` | main | independent extracted candidate repository; implementation/public-contract authority transition incomplete | extracted repo exists; forge candidate remains `research/epac/` until release/reconsumption; `libs/epac/` remains unpopulated | @@ -46,6 +47,7 @@ release identity. | Workspace | Participant | Exact commit | Relation | Canonical release | |---|---|---|---|---| +| `research/english-gonol/` | `The-Interdependency/stack` | `030022948fb7c749961ae65743a4448c4bb6cbbe` | stack-local English lexical/gonol construction separated from EDCM; consumes UCNS geometry; EDCM may evaluate outputs but does not define construction | no | | `research/from-photons-to-macroverse/` | `The-Interdependency/stack` | `77ef8c7fb0ff75a524181655ee9f9641372768f7` | target composition forge baseline at audit start | no | | `research/from-photons-to-macroverse/` | `The-Interdependency/skill-lib` | `61eb3b14db440e6ee9b7bf8de3b646dbfd00fb32` | audit, domain-claim, work-graph, and hmmm doctrine | no | | `research/from-photons-to-macroverse/` | `The-Interdependency/metapat` | `d6699e21b11c8f8394998efc34a468e2d6efc8b0` | domain-restraint authority; root impact none | no | @@ -68,7 +70,10 @@ Each established `research//` workspace carries a `BASE.json` with: - authority owner; - standing `stack-local-research`. -Use that record before interpreting or extending work in the workspace. +A newly separated stack-local component may instead preserve the repository it was +extracted from as provenance while declaring a distinct `project` and stack-local +authority. Such a component must also appear in the stack research-participant graph; +its source repository must stop claiming the separated responsibility at stack level. EPAC is currently an extraction-transition exception: the independent repository exists, but authority transfer is not complete, so the forge candidate remains in `research/epac/` @@ -104,8 +109,10 @@ rm -rf libs//* git -C archive | tar -x -C libs// ``` -Then update this file, `stack-manifest.json`, and `research//BASE.json`; recompute -the work-graph digest; and commit with the new source commit SHA. +Then update this file, `stack-manifest.json`, and the matching +`research//BASE.json`; recompute the work-graph digest; and commit with the new +source commit SHA. Structural ownership/relation changes must additionally follow the +`stack-update` skill and pass `python tools/check_stack_consistency.py`. Do not edit `libs//` to create a canonical change. Route the change to the owning repository, merge it there, then refresh the pinned view. @@ -117,8 +124,12 @@ Do not populate `libs/epac/`, replace the forge candidate, or assert implementat authority transfer until EPAC completes its clean build/install, license/distribution, immutable release, downstream stack reconsumption, and authority-transition receipt gates. +English Gonol Construction is earlier in that lifecycle: it is a distinct stack-local +research component, not EDCM and not an independent canonical release. + ## hmmm - UCNS has no `LICENSE` file at pinned commit `828c0b8`. - EPAC clean install, license, stable release, downstream reconsumption, and authority-transition receipt remain incomplete; `libs/epac/` stays unpopulated until graduation. +- English Gonol Construction remains stack-local research; independent repository/release authority has not been established. - `skill-lib/` remains a special operational snapshot at stack root rather than following the ordinary `libs/` + `research/` pair. From 46496a030e0045ff69ee8e83ebc03574209d03db Mon Sep 17 00:00:00 2001 From: Erin Spencer Date: Fri, 11 Sep 2026 23:39:07 -0700 Subject: [PATCH 03/15] docs(stack): document English Gonol and structural update gate --- README.md | 45 +++++++++++++++++++++++++++++++++++++-------- 1 file changed, 37 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index dd7ba78..9c4b19d 100644 --- a/README.md +++ b/README.md @@ -20,6 +20,7 @@ For repositories with an independent authority: ```text stack/ ├── skill-lib/ # operational pinned snapshot of org build/evidence doctrine +├── .agents/skills/ # repo-local consumed skills; stack-update guards structural changes ├── libs/ # manifest-pinned canonical repository views; do not edit │ ├── metapat/ │ ├── ucns/ @@ -31,7 +32,8 @@ stack/ ├── research/ # stack-local work; never source authority by location │ ├── metapat/ # current METAPAT research + BASE.json │ ├── ucns/ # current UCNS research + BASE.json -│ ├── edcm/ # current EDCM research + BASE.json +│ ├── english-gonol/ # English lexical/gonol construction; distinct from EDCM +│ ├── edcm/ # current EDCM measurement research + BASE.json │ ├── pcea/ # current PCEA research + BASE.json │ ├── ptcna/ # current PTCNA research + BASE.json │ ├── epac/ # extracted candidate remains forge-side until graduation completes @@ -41,6 +43,8 @@ stack/ ├── backend/ # PostgreSQL-backed durable fresh-making control plane ├── frontend/ │ └── cli/ # human control/status surface for backend +├── tools/ +│ └── check_stack_consistency.py # deterministic authority/provenance drift gate ├── STACK_MANIFEST.md # human-readable provenance and boundary record └── stack-manifest.json # machine-readable work graph ``` @@ -68,6 +72,27 @@ cat research/ucns/BASE.json If the result changes UCNS itself, prepare the change for `The-Interdependency/ucns`. After upstream merge, refresh `libs/ucns/` and update `research/ucns/BASE.json`. +English Gonol Construction is a separated stack-local component at +`research/english-gonol/`. UCNS owns its consumed geometry. English Gonol owns the +English text-domain construction candidate. EDCM may evaluate those outputs but does +not define the construction. + +### Change stack structure + +Any change that alters a participant, pin, authority, relation, research workspace, +extraction/graduation standing, `BASE.json`, or architecture projection must load the +`stack-update` skill and finish as one coherent stack transaction. + +Run the deterministic gate before and after the mutation: + +```bash +python tools/check_stack_consistency.py +``` + +A structural change is not complete merely because moved code or local tests pass. The +machine manifest, human manifest, affected base records, architecture description, and +work-graph digest must agree before merge. + ### Compose something new New cross-project work may be born in stack. It does not inherit the authority of its @@ -76,11 +101,12 @@ coherent enough to graduate, create its independent repository, preserve provena package/release it, then let stack consume the released project rather than a hidden stack-local implementation. -EPAC and psychsocio metafauna are currently in this pre-graduation state. EPAC -has an independent extracted repository, but extraction is not graduation: its -forge research remains here until EPAC completes its release, downstream -reconsumption, and authority-transition gates. From Photons to the Macroverse is -also stack-local pre-graduation research. +English Gonol Construction is currently a distinct stack-local research component, +separated from EDCM but not independently graduated. EPAC and psychsocio metafauna are +also pre-graduation work, with EPAC further along: EPAC has an independent extracted +repository, but extraction is not graduation, so its forge research remains here until +EPAC completes its release, downstream reconsumption, and authority-transition gates. +From Photons to the Macroverse is also stack-local pre-graduation research. ### Make derived artifacts fresh without depending on hosted CI @@ -122,7 +148,8 @@ git -C archive | tar -x -C libs// Then update `STACK_MANIFEST.md`, `stack-manifest.json`, and the matching `research//BASE.json`; recompute the work-graph digest; and commit with the exact -source commit in the message. +source commit in the message. Run `python tools/check_stack_consistency.py` before +merge. ## Boundaries @@ -132,7 +159,7 @@ source commit in the message. populated only from an owning canonical repository at an exact commit. - proof, measurement, semantic, empirical, and certification standing do not transfer merely because projects are composed in stack. -- `backend/` may coordinate an owning repository but does not acquire that repository's +- backend may coordinate an owning repository but does not acquire that repository's authority. - PostgreSQL owns orchestration/freshness evidence, not repository artifacts or canon. - executor success alone cannot establish freshness; the declared verifier and accepted @@ -147,6 +174,8 @@ source commit in the message. `libs/` + `research/` pair. - The exact graduation automation from stack-local project to independent repo + package is not yet implemented. +- English Gonol Construction has distinct stack-local authority but has not yet gained an + independent repository/release authority boundary. - Actual VM PostgreSQL/service-account/storage state and the independent backup device remain deployment observations until inspected on the VM. - A GitHub-hosted executor remains optional and unimplemented; VM-local execution is the From c5ed35ed40a36b544a5be0f4aad519878f3c3254 Mon Sep 17 00:00:00 2001 From: Erin Spencer Date: Fri, 11 Sep 2026 23:40:10 -0700 Subject: [PATCH 04/15] feat(stack): add deterministic structural consistency checker --- tools/check_stack_consistency.py | 243 +++++++++++++++++++++++++++++++ 1 file changed, 243 insertions(+) create mode 100644 tools/check_stack_consistency.py diff --git a/tools/check_stack_consistency.py b/tools/check_stack_consistency.py new file mode 100644 index 0000000..0de7de5 --- /dev/null +++ b/tools/check_stack_consistency.py @@ -0,0 +1,243 @@ +# === MODULE_BUILD === +# id: stack_consistency_checker +# module_name: check_stack_consistency +# module_kind: verification-tool +# summary: fail-closed structural consistency checks across stack manifests, research bases, authority projections, and work-graph identity +# owner: The-Interdependency/stack +# public_surface: command-line exit status and human-readable findings +# internal_surface: manifest digest, repository/base cross-checks, separated-component checks +# auth_boundary: none +# storage_boundary: read-only repository files +# network_boundary: none +# user_data_boundary: none +# admin_only: false +# tests: exercised in .github/workflows/stack-consistency.yml and by local invocation +# rollout: required structural drift gate +# rollback: revert checker/workflow together only if replaced by an equivalent or stricter gate +# requires: Python standard library, stack-manifest.json, STACK_MANIFEST.md +# since: 2026-09-12 +# unresolved: semantic responsibility cannot be inferred exhaustively from source code +# === END MODULE_BUILD === + +# === CONTRACTS === +# id: stack_work_graph_digest_reproduces +# given: stack-manifest.json declares repositories, research_participants, boundaries, and work_graph_sha256 +# then: canonical JSON over the three hashed fields reproduces the declared SHA-256 exactly +# class: evidence +# since: 2026-09-12 +# +# id: stack_human_machine_authority_agree +# given: stack-manifest.json and STACK_MANIFEST.md describe repository participants +# then: every machine-declared repository identity, commit, and authority is represented in the human manifest +# class: evidence +# since: 2026-09-12 +# +# id: separated_stack_component_has_graph_identity +# given: a research BASE.json declares a project name distinct from its source repository name +# then: the project has an explicit research_participants record and the former source owner does not retain a known superseded authority claim +# class: boundary +# since: 2026-09-12 +# === END CONTRACTS === + +"""Verify stack authority/provenance projections agree. + +Usage guidance +-------------- +Run from the repository root before and after any structural stack mutation:: + + python tools/check_stack_consistency.py + +The command is intentionally read-only and stdlib-only. Exit status 0 means the +checks implemented here agree; it does not promote research to canon or prove any +scientific, semantic, measurement, or graduation claim. +""" + +from __future__ import annotations + +import hashlib +import json +import re +import sys +from pathlib import Path +from typing import Any + +ROOT = Path(__file__).resolve().parents[1] +MANIFEST_PATH = ROOT / "stack-manifest.json" +HUMAN_MANIFEST_PATH = ROOT / "STACK_MANIFEST.md" +README_PATH = ROOT / "README.md" +HASHED_FIELDS = ("repositories", "research_participants", "boundaries") +HEX40 = re.compile(r"^[0-9a-f]{40}$") + + +def load_json(path: Path) -> dict[str, Any]: + return json.loads(path.read_text(encoding="utf-8")) + + +def manifest_digest(manifest: dict[str, Any]) -> str: + payload = {key: manifest[key] for key in HASHED_FIELDS} + encoded = json.dumps(payload, sort_keys=True, separators=(",", ":")).encode("utf-8") + return hashlib.sha256(encoded).hexdigest() + + +def error(findings: list[str], code: str, message: str) -> None: + findings.append(f"{code}: {message}") + + +def check_manifest_shape(manifest: dict[str, Any], findings: list[str]) -> None: + if manifest.get("schema") != "the-interdependency.stack-manifest": + error(findings, "manifest.schema", "unexpected or missing stack-manifest schema") + for key in (*HASHED_FIELDS, "work_graph_sha256"): + if key not in manifest: + error(findings, "manifest.missing", f"missing required field {key!r}") + for entry in manifest.get("repositories", []): + commit = entry.get("commit", "") + if not HEX40.fullmatch(commit): + error(findings, "repository.commit", f"{entry.get('repository')}: invalid commit {commit!r}") + for entry in manifest.get("research_participants", []): + commit = entry.get("commit", "") + if not HEX40.fullmatch(commit): + error(findings, "research.commit", f"{entry.get('workspace')}:{entry.get('participant_id')}: invalid commit {commit!r}") + if entry.get("authority_transfer") is not False: + error(findings, "research.authority_transfer", f"{entry.get('workspace')}:{entry.get('participant_id')} must keep authority_transfer=false") + + +def check_digest(manifest: dict[str, Any], human: str, findings: list[str]) -> None: + try: + actual = manifest_digest(manifest) + except KeyError as exc: + error(findings, "digest.input", f"cannot compute digest; missing {exc.args[0]!r}") + return + declared = manifest.get("work_graph_sha256", "") + if declared != actual: + error(findings, "digest.mismatch", f"declared {declared!r}, recomputed {actual!r}") + if declared and declared not in human: + error(findings, "digest.human_drift", "STACK_MANIFEST.md does not carry the machine-declared work-graph digest") + + +def check_repository_projection(manifest: dict[str, Any], human: str, findings: list[str]) -> dict[str, dict[str, Any]]: + index: dict[str, dict[str, Any]] = {} + for entry in manifest.get("repositories", []): + repository = entry.get("repository", "") + if repository in index: + error(findings, "repository.duplicate", f"duplicate manifest repository {repository!r}") + continue + index[repository] = entry + for field in (repository, entry.get("commit", ""), entry.get("authority", "")): + if field and field not in human: + error(findings, "repository.human_drift", f"STACK_MANIFEST.md is missing {repository!r} projection value {field!r}") + return index + + +def check_research_participants(manifest: dict[str, Any], human: str, findings: list[str]) -> set[tuple[str, str]]: + seen: set[tuple[str, str]] = set() + for entry in manifest.get("research_participants", []): + key = (entry.get("workspace", ""), entry.get("participant_id", "")) + if key in seen: + error(findings, "research.duplicate", f"duplicate research participant {key!r}") + seen.add(key) + workspace = entry.get("workspace", "") + commit = entry.get("commit", "") + if workspace and workspace not in human: + error(findings, "research.human_drift", f"STACK_MANIFEST.md does not mention workspace {workspace!r}") + if commit and commit not in human: + error(findings, "research.human_drift", f"STACK_MANIFEST.md does not mention research commit {commit!r}") + return seen + + +def check_base_records( + repositories: dict[str, dict[str, Any]], + research_participants: set[tuple[str, str]], + readme: str, + findings: list[str], +) -> None: + research_root = ROOT / "research" + if not research_root.exists(): + error(findings, "research.missing", "research/ directory is missing") + return + + for base_path in sorted(research_root.glob("*/BASE.json")): + base = load_json(base_path) + workspace_name = base_path.parent.name + workspace = f"research/{workspace_name}/" + project = str(base.get("project", workspace_name)) + source_repository = str(base.get("source_repository", "")) + source_commit = str(base.get("source_commit", "")) + source_entry = repositories.get(source_repository) + + if source_entry and source_commit != source_entry.get("commit"): + error( + findings, + "base.source_drift", + f"{base_path.relative_to(ROOT)} pins {source_repository}@{source_commit}, manifest pins {source_entry.get('commit')}", + ) + + source_name = source_repository.rsplit("/", 1)[-1] if source_repository else "" + if project and source_name and project != source_name: + if (workspace, project) not in research_participants: + error( + findings, + "base.separated_unrepresented", + f"{workspace} declares separated project {project!r} from source {source_repository!r} but has no matching research_participants record", + ) + if f"{workspace_name}/" not in readme and workspace not in readme: + error(findings, "base.readme_drift", f"README.md does not expose separated workspace {workspace!r}") + + +def check_english_gonol_regression( + repositories: dict[str, dict[str, Any]], + research_participants: set[tuple[str, str]], + human: str, + readme: str, + findings: list[str], +) -> None: + base_path = ROOT / "research" / "english-gonol" / "BASE.json" + if not base_path.exists(): + return + + edcm = repositories.get("The-Interdependency/edcm") + if edcm is None: + error(findings, "english_gonol.edcm_missing", "EDCM is absent from repositories manifest") + return + + authority = str(edcm.get("authority", "")).lower() + if "gonol construction" in authority or "text-gonol construction" in authority: + error(findings, "english_gonol.stale_edcm_authority", "EDCM still claims English/text gonol construction authority after separation") + + expected = ("research/english-gonol/", "english-gonol") + if expected not in research_participants: + error(findings, "english_gonol.graph_missing", "English Gonol is missing its explicit stack research-participant identity") + + for surface_name, surface in (("STACK_MANIFEST.md", human), ("README.md", readme)): + if "research/english-gonol/" not in surface and "english-gonol/" not in surface: + error(findings, "english_gonol.projection_missing", f"{surface_name} does not expose English Gonol's separated workspace") + + +def main() -> int: + findings: list[str] = [] + try: + manifest = load_json(MANIFEST_PATH) + human = HUMAN_MANIFEST_PATH.read_text(encoding="utf-8") + readme = README_PATH.read_text(encoding="utf-8") + except (OSError, json.JSONDecodeError) as exc: + print(f"stack consistency: fail: unable to read required inputs: {exc}") + return 1 + + check_manifest_shape(manifest, findings) + check_digest(manifest, human, findings) + repositories = check_repository_projection(manifest, human, findings) + research_participants = check_research_participants(manifest, human, findings) + check_base_records(repositories, research_participants, readme, findings) + check_english_gonol_regression(repositories, research_participants, human, readme, findings) + + if findings: + for finding in findings: + print(f"error: {finding}") + print(f"stack consistency: fail ({len(findings)} error(s))") + return 1 + + print(f"stack consistency: pass ({len(repositories)} repositories, {len(research_participants)} research participant identities)") + return 0 + + +if __name__ == "__main__": + sys.exit(main()) From c69b4e77eca97c42944d4e5ecec6fae4e95f55dd Mon Sep 17 00:00:00 2001 From: Erin Spencer Date: Fri, 11 Sep 2026 23:40:18 -0700 Subject: [PATCH 05/15] ci(stack): enforce structural consistency --- .github/workflows/stack-consistency.yml | 37 +++++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 .github/workflows/stack-consistency.yml diff --git a/.github/workflows/stack-consistency.yml b/.github/workflows/stack-consistency.yml new file mode 100644 index 0000000..3b0f5c8 --- /dev/null +++ b/.github/workflows/stack-consistency.yml @@ -0,0 +1,37 @@ +name: stack-consistency + +on: + pull_request: + paths: + - 'stack-manifest.json' + - 'STACK_MANIFEST.md' + - 'README.md' + - 'AGENTS.md' + - 'research/**' + - 'libs/**' + - 'tools/check_stack_consistency.py' + - '.agents/skills/stack-update/**' + - '.github/workflows/stack-consistency.yml' + push: + branches: [main] + paths: + - 'stack-manifest.json' + - 'STACK_MANIFEST.md' + - 'README.md' + - 'AGENTS.md' + - 'research/**' + - 'libs/**' + - 'tools/check_stack_consistency.py' + - '.agents/skills/stack-update/**' + - '.github/workflows/stack-consistency.yml' + +permissions: + contents: read + +jobs: + consistency: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Verify stack authority and provenance projections + run: python tools/check_stack_consistency.py From 64f8eec7aa248d0aed0bf407ecbd83f657059129 Mon Sep 17 00:00:00 2001 From: Erin Spencer Date: Fri, 11 Sep 2026 23:40:42 -0700 Subject: [PATCH 06/15] feat(stack): vendor stack-update skill --- .agents/skills/stack-update/SKILL.md | 156 +++++++++++++++++++++++++++ 1 file changed, 156 insertions(+) create mode 100644 .agents/skills/stack-update/SKILL.md diff --git a/.agents/skills/stack-update/SKILL.md b/.agents/skills/stack-update/SKILL.md new file mode 100644 index 0000000..a1e9148 --- /dev/null +++ b/.agents/skills/stack-update/SKILL.md @@ -0,0 +1,156 @@ +--- +name: stack-update +description: Fail-closed update protocol for The-Interdependency/stack. Load this when a stack change adds, moves, extracts, graduates, renames, removes, or changes the authority, relation, source identity, or placement of a participant, research workspace, libs pin, BASE record, stack manifest entry, or architecture description; when stack-manifest.json, STACK_MANIFEST.md, README.md, or research BASE.json files may drift from one another; or when validating that a structural stack change is complete before commit or merge. +--- + +# stack-update — change the stack as one coherent transaction + +Use this procedural skill for structural changes to `The-Interdependency/stack`. +It specializes `interdependent-work-graph`; it does not replace that skill or +`project-incubation-graduation`. + +## Core contract + +A stack change that alters **identity, ownership, authority, relation, lifecycle, +or placement** is incomplete until every affected authority/provenance projection +agrees and the deterministic stack-consistency checker passes. + +```text +structural mutation + -> classify affected authority and relations + -> update owning source and stack projections + -> recompute machine identity + -> validate local + cross-boundary consistency + -> commit only when coherent +``` + +Location never creates authority. A successful move, import, extraction, or test +run does not itself update ownership, canon, proof status, measurement validity, +or graduation standing. + +## Trigger / non-trigger + +Load this skill when a change touches any of these surfaces or their meaning: + +- `libs//` pins or imported canonical views; +- `research//` creation, deletion, rename, extraction, or lifecycle; +- `research/*/BASE.json` provenance or authority; +- `stack-manifest.json` / `STACK_MANIFEST.md` participants, authorities, relations, + boundaries, or work-graph digest; +- root architecture descriptions in `README.md` or `AGENTS.md`; +- an emergent project moving toward or away from independent-repository authority. + +Do not load it for an ordinary implementation edit whose owning repository, +workspace, authority, manifest identities, and architecture relations do not change. + +## Required companion skills + +1. Load `interdependent-work-graph` for every structural stack mutation. +2. Load `project-incubation-graduation` when extraction, release, reconsumption, + graduation, or implementation-authority transition is involved. +3. Load `the-interdependency` for organization workflow and GitHub hygiene. +4. Consult current METAPAT only when the change requires choosing a new conceptual + distinction or authority relation rather than implementing an already-fixed one. + +## Workflow + +1. **Freeze the starting identity.** Record the exact stack commit and every + producer/source commit whose authority can affect the change. +2. **Classify the mutation.** Mark each affected item as one or more of: + `identity`, `authority`, `relation`, `placement`, `lifecycle`, `pin`, `projection`. +3. **Resolve edit ownership.** Change a claim at its owning source. Never repair a + producer-owned defect by shadowing it in a consumer or by editing `libs/`. +4. **Compute the update closure.** Inspect at minimum: + `stack-manifest.json`, `STACK_MANIFEST.md`, root `README.md`, root `AGENTS.md`, + the affected `research/*/BASE.json`, relevant local README/docs, and CI/checkers. + Update every projection whose statement became false because of the mutation. +5. **Remove superseded claims.** A newly separated owner requires the prior owner to + stop claiming that responsibility in every stack-level authority projection. + Do not merely add the new owner alongside stale text. +6. **Preserve lifecycle standing.** Extraction is not graduation. Stack-local work + remains noncanonical until its governing graduation gates complete and stack + reconsumes the released independent artifact where required. +7. **Recompute machine identity.** Recompute `work_graph_sha256` exactly from the + versioned manifest contract after any hashed field changes. Never hand-wave or + copy an old digest. +8. **Run deterministic consistency validation.** In stack, run: + + ```bash + python tools/check_stack_consistency.py + ``` + + Treat any error as a blocked structural update, not a documentation warning. +9. **Run affected behavioral gates.** Execute repository/workspace-local tests and + at least one cross-boundary check for changed producer/consumer relations. +10. **Commit the transaction.** The structural mutation and its required projections + belong in one coherent PR/merge sequence. If a necessary authority is unavailable, + preserve the boundary as `hmmm`; do not guess it into consistency. + +## Deterministic checker contract + +A consuming stack checker should fail closed for at least: + +- a `work_graph_sha256` that does not reproduce from the declared manifest fields; +- disagreement between machine-readable and human-readable repository authority; +- direct tracked edits to `libs/` presented as stack-owned canon; +- an affected `BASE.json` whose source repository/commit conflicts with the pinned + source identity it claims to derive from; +- an emergent stack-local component whose authority separation is declared locally + while stack-level authority text still assigns that responsibility to its former owner; +- lifecycle language that treats extraction as graduation; +- a structural update that changes one required projection but omits another. + +The checker validates coherence, not truth of scientific or semantic claims. Those +remain owned by their proper repositories and evidence. + +## Output shape + +When this skill is active, report: + +```markdown +## Stack transaction +- start identity: +- mutation class: +- affected authority / relations: +- files changed: + +## Validation +- stack consistency: +- local gates: +- cross-boundary gate: + +## Standing +- canon / research / extracted / graduated: +- hmmm: +``` + +## Usage guidance + +Before moving or separating a stack component, run the checker once **before** the +change to establish the current baseline, make the structural edit and all required +projection updates, then run it again. A pre-existing failure is evidence to classify; +it is not permission to add another inconsistency. + +Example: moving English Gonol Construction out of EDCM requires the new workspace and +its provenance **and** removal of `text-gonol construction` from EDCM's stack-level +authority statement, corresponding manifest/work-graph updates, digest regeneration, +and the affected English Gonol + EDCM checks. + +## Anti-patterns + +- Moving code first and treating manifest/docs repair as optional cleanup. +- Updating `stack-manifest.json` but not `STACK_MANIFEST.md`, or vice versa. +- Adding a new authority statement without removing the superseded one. +- Editing `libs//` to make a stack-local inconsistency disappear. +- Reusing a stale work-graph digest after changing hashed fields. +- Calling an extracted project graduated because the new repository exists. +- Making CI green by widening `PYTHONPATH` or weakening checks instead of repairing + ownership/provenance drift. + +## hmmm + +- The first stack checker is intentionally conservative: it can prove declared + projections agree, but it cannot infer every semantic responsibility from source code. +- Future schema revisions may carry explicit typed stack-local component records and + edge lists so more structural obligations can be checked without text comparisons. +- A checklist that never fails a build eventually becomes wall decoration. From b02d515ef8a4b710095d55f621d517c44fa1e98b Mon Sep 17 00:00:00 2001 From: Erin Spencer Date: Fri, 11 Sep 2026 23:41:00 -0700 Subject: [PATCH 07/15] docs(stack): require stack-update skill for structural mutations --- AGENTS.md | 35 ++++++++++++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/AGENTS.md b/AGENTS.md index f7cd044..3108062 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -10,6 +10,9 @@ projects may later graduate into their own repositories. inside stack; canonical edits happen in the owning repository. - `research//` is current stack-local research against an exact pinned base. It is not canon merely because it is in stack. +- `research/english-gonol/` is a distinct stack-local English lexical/gonol construction + component. UCNS owns consumed geometry; EDCM may evaluate outputs but does not define + the English Gonol construction. - root-level emerging projects such as `ahbg/` may be close to external repo-hood; root placement does not transfer authority from their inputs. - `STACK_MANIFEST.md` and `stack-manifest.json` own stack-level participant provenance. @@ -18,6 +21,27 @@ projects may later graduate into their own repositories. - `skill-lib/` is the currently pinned operational skill snapshot; exact newer doctrine may be bound separately only when its provenance and non-transfer boundary are explicit. +## Structural update gate + +Before adding, moving, separating, extracting, graduating, renaming, removing, or +changing the authority/relation/pin of a stack participant or research workspace, load: + +```text +.agents/skills/stack-update/SKILL.md +``` + +Also resolve the applicable `interdependent-work-graph` doctrine and, for lifecycle +transitions, `project-incubation-graduation`. Structural changes are one transaction: +update every affected machine/human authority projection, remove superseded ownership +claims, recompute the work-graph digest, and pass: + +```bash +python tools/check_stack_consistency.py +``` + +Do not treat moved code, passing local tests, or a new repository as sufficient evidence +that stack authority/provenance records are current. + ## Fresh-making boundary PostgreSQL on the VM is the single production state authority for derivation specs, @@ -50,6 +74,12 @@ namespace is deprecated and removed; use `stackctl fresh ...`. ## Checks +Structural stack consistency: + +```bash +python tools/check_stack_consistency.py +``` + Fresh-making/backend checks that can run without PostgreSQL: ```bash @@ -65,13 +95,16 @@ PostgreSQL integration checks require an explicitly disposable database. A skipp integration check is `hmmm`, not a pass. AHBG/Grok has its own local suites under `ahbg/grok/`; run those when touching that -workspace. Do not claim root manifest-check tooling that is not present in this branch. +workspace. The root stack-consistency checker verifies declared authority/provenance +coherence; it does not replace workspace behavioral tests. ## hmmm - Concrete VM PostgreSQL/auth/service-account/storage and backup-mount acceptance remains unobserved until checked on the VM. - Organization aggregate and website-projection derivation specs are not yet registered. +- English Gonol Construction has distinct stack-local authority but has not yet gained an + independent repository/release authority boundary. - The complete root `skill-lib/` snapshot refresh remains separate because the current provenance-bound fresh-making doctrine is newer than the local generator snapshot. - Project graduation automation remains unimplemented. From 0e4a3f8e3e436a58a5070ca3e573f70f7fb642d9 Mon Sep 17 00:00:00 2001 From: Erin Spencer Date: Fri, 11 Sep 2026 23:51:45 -0700 Subject: [PATCH 08/15] fix(stack): make UCNS research base explicit in work graph --- stack-manifest.json | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/stack-manifest.json b/stack-manifest.json index 58693da..e205464 100644 --- a/stack-manifest.json +++ b/stack-manifest.json @@ -1,7 +1,7 @@ { "schema": "the-interdependency.stack-manifest", "version": "1.1.0", - "work_graph_sha256": "aa979936a351d2331cf8079939bba5ecb0bc9d694a29badd17335dad6afb2086", + "work_graph_sha256": "9ab3b3f75a32f5f73b5df68419148181fc632593babe4ec6adf4269d4f35badb", "repositories": [ { "repository": "The-Interdependency/skill-lib", @@ -130,6 +130,15 @@ "relation": "stack-local English lexical/gonol construction separated from EDCM; consumes UCNS geometry; EDCM may evaluate outputs but does not define construction", "canonical_release": false, "authority_transfer": false + }, + { + "workspace": "research/ucns/", + "participant_id": "ucns-source-base", + "repository": "The-Interdependency/ucns", + "commit": "1975fe70cf4e0826a8020c2da3047569e277af64", + "relation": "explicit source base for integrated stack-local UCNS research; does not refresh or replace the manifest-pinned libs/ucns canonical view", + "canonical_release": false, + "authority_transfer": false } ] } From 2415ed26a61c723fea60f328745646f2b753796e Mon Sep 17 00:00:00 2001 From: Erin Spencer Date: Fri, 11 Sep 2026 23:52:26 -0700 Subject: [PATCH 09/15] docs(stack): record explicit UCNS research base --- STACK_MANIFEST.md | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/STACK_MANIFEST.md b/STACK_MANIFEST.md index f09445f..80b03e8 100644 --- a/STACK_MANIFEST.md +++ b/STACK_MANIFEST.md @@ -9,7 +9,7 @@ Provenance and authority-boundary record for `The-Interdependency/stack`. - English Gonol separation reconciliation UTC: `2026-09-12` at `030022948fb7c749961ae65743a4448c4bb6cbbe` - Stack-manifest schema: `the-interdependency.stack-manifest` version `1.1.0` - Work-graph digest (SHA-256 over canonical `repositories` + `research_participants` + `boundaries` JSON): - `aa979936a351d2331cf8079939bba5ecb0bc9d694a29badd17335dad6afb2086` + `9ab3b3f75a32f5f73b5df68419148181fc632593babe4ec6adf4269d4f35badb` - Machine-readable copy: [`stack-manifest.json`](stack-manifest.json) ## Directory contract @@ -18,12 +18,16 @@ For an established repository participating in stack: ```text libs// = exact imported canonical repository view at the manifest commit -research// = mutable stack-local research based on that imported view +research// = mutable stack-local research bound to an explicit source identity ``` `libs/` does not gain authority by containing a copy. The owning repository remains canonical. `research/` does not gain canon status by producing a useful result. +A research workspace normally shares the imported `libs//` pin. If it intentionally +uses a different exact source commit, that source identity must be represented explicitly +in `research_participants`; it does not silently refresh or replace the `libs/` pin. + A Python `src/` directory inside `libs//` retains the normal package-layout meaning used by that repository. @@ -48,6 +52,7 @@ release identity. | Workspace | Participant | Exact commit | Relation | Canonical release | |---|---|---|---|---| | `research/english-gonol/` | `The-Interdependency/stack` | `030022948fb7c749961ae65743a4448c4bb6cbbe` | stack-local English lexical/gonol construction separated from EDCM; consumes UCNS geometry; EDCM may evaluate outputs but does not define construction | no | +| `research/ucns/` | `The-Interdependency/ucns` | `1975fe70cf4e0826a8020c2da3047569e277af64` | explicit source base for integrated stack-local UCNS research; does not refresh or replace the manifest-pinned `libs/ucns` canonical view | no | | `research/from-photons-to-macroverse/` | `The-Interdependency/stack` | `77ef8c7fb0ff75a524181655ee9f9641372768f7` | target composition forge baseline at audit start | no | | `research/from-photons-to-macroverse/` | `The-Interdependency/skill-lib` | `61eb3b14db440e6ee9b7bf8de3b646dbfd00fb32` | audit, domain-claim, work-graph, and hmmm doctrine | no | | `research/from-photons-to-macroverse/` | `The-Interdependency/metapat` | `d6699e21b11c8f8394998efc34a468e2d6efc8b0` | domain-restraint authority; root impact none | no | @@ -64,12 +69,19 @@ VCS metadata, virtualenvs, caches, and untracked files are excluded. Each established `research//` workspace carries a `BASE.json` with: -- owning repository; +- owning/source repository; - exact source commit; -- matching `libs//` canon path; +- canon path when one exists; - authority owner; - standing `stack-local-research`. +When `BASE.json.source_commit` differs from the repository's manifest-pinned `libs/` +commit, the workspace must carry an explicit matching `research_participants` identity. +That record preserves the newer/different research input without pretending `libs/` was +refreshed. `research/ucns/` currently uses this form: its exact source base is UCNS +`1975fe70cf4e0826a8020c2da3047569e277af64`, while `libs/ucns/` remains pinned at +`828c0b8bbcfc267efb5701da714191c1f73a81ff`. + A newly separated stack-local component may instead preserve the repository it was extracted from as provenance while declaring a distinct `project` and stack-local authority. Such a component must also appear in the stack research-participant graph; From 627eeab2f1fec077b5b1d04badaff55bae04d2b9 Mon Sep 17 00:00:00 2001 From: Erin Spencer Date: Fri, 11 Sep 2026 23:53:07 -0700 Subject: [PATCH 10/15] fix(stack): require explicit alternate research source identities --- tools/check_stack_consistency.py | 59 ++++++++++++++++++++------------ 1 file changed, 38 insertions(+), 21 deletions(-) diff --git a/tools/check_stack_consistency.py b/tools/check_stack_consistency.py index 0de7de5..bef29ba 100644 --- a/tools/check_stack_consistency.py +++ b/tools/check_stack_consistency.py @@ -32,6 +32,12 @@ # class: evidence # since: 2026-09-12 # +# id: alternate_research_source_is_explicit +# given: a research BASE.json source commit differs from its repository's manifest-pinned libs commit +# then: the workspace carries an explicit matching research_participants source identity rather than silently rebasing the libs pin +# class: boundary +# since: 2026-09-12 +# # id: separated_stack_component_has_graph_identity # given: a research BASE.json declares a project name distinct from its source repository name # then: the project has an explicit research_participants record and the former source owner does not retain a known superseded authority claim @@ -128,25 +134,34 @@ def check_repository_projection(manifest: dict[str, Any], human: str, findings: return index -def check_research_participants(manifest: dict[str, Any], human: str, findings: list[str]) -> set[tuple[str, str]]: - seen: set[tuple[str, str]] = set() +def check_research_participants( + manifest: dict[str, Any], + human: str, + findings: list[str], +) -> tuple[set[tuple[str, str]], set[tuple[str, str, str]]]: + keys: set[tuple[str, str]] = set() + sources: set[tuple[str, str, str]] = set() for entry in manifest.get("research_participants", []): - key = (entry.get("workspace", ""), entry.get("participant_id", "")) - if key in seen: + workspace = str(entry.get("workspace", "")) + participant_id = str(entry.get("participant_id", "")) + repository = str(entry.get("repository", "")) + commit = str(entry.get("commit", "")) + key = (workspace, participant_id) + if key in keys: error(findings, "research.duplicate", f"duplicate research participant {key!r}") - seen.add(key) - workspace = entry.get("workspace", "") - commit = entry.get("commit", "") + keys.add(key) + sources.add((workspace, repository, commit)) if workspace and workspace not in human: error(findings, "research.human_drift", f"STACK_MANIFEST.md does not mention workspace {workspace!r}") if commit and commit not in human: error(findings, "research.human_drift", f"STACK_MANIFEST.md does not mention research commit {commit!r}") - return seen + return keys, sources def check_base_records( repositories: dict[str, dict[str, Any]], - research_participants: set[tuple[str, str]], + research_participant_keys: set[tuple[str, str]], + research_source_identities: set[tuple[str, str, str]], readme: str, findings: list[str], ) -> None: @@ -165,15 +180,17 @@ def check_base_records( source_entry = repositories.get(source_repository) if source_entry and source_commit != source_entry.get("commit"): - error( - findings, - "base.source_drift", - f"{base_path.relative_to(ROOT)} pins {source_repository}@{source_commit}, manifest pins {source_entry.get('commit')}", - ) + explicit_source = (workspace, source_repository, source_commit) + if explicit_source not in research_source_identities: + error( + findings, + "base.source_drift", + f"{base_path.relative_to(ROOT)} pins {source_repository}@{source_commit}, manifest libs pin is {source_entry.get('commit')}, and no matching research_participants source identity exists", + ) source_name = source_repository.rsplit("/", 1)[-1] if source_repository else "" if project and source_name and project != source_name: - if (workspace, project) not in research_participants: + if (workspace, project) not in research_participant_keys: error( findings, "base.separated_unrepresented", @@ -185,7 +202,7 @@ def check_base_records( def check_english_gonol_regression( repositories: dict[str, dict[str, Any]], - research_participants: set[tuple[str, str]], + research_participant_keys: set[tuple[str, str]], human: str, readme: str, findings: list[str], @@ -204,7 +221,7 @@ def check_english_gonol_regression( error(findings, "english_gonol.stale_edcm_authority", "EDCM still claims English/text gonol construction authority after separation") expected = ("research/english-gonol/", "english-gonol") - if expected not in research_participants: + if expected not in research_participant_keys: error(findings, "english_gonol.graph_missing", "English Gonol is missing its explicit stack research-participant identity") for surface_name, surface in (("STACK_MANIFEST.md", human), ("README.md", readme)): @@ -225,9 +242,9 @@ def main() -> int: check_manifest_shape(manifest, findings) check_digest(manifest, human, findings) repositories = check_repository_projection(manifest, human, findings) - research_participants = check_research_participants(manifest, human, findings) - check_base_records(repositories, research_participants, readme, findings) - check_english_gonol_regression(repositories, research_participants, human, readme, findings) + research_participant_keys, research_source_identities = check_research_participants(manifest, human, findings) + check_base_records(repositories, research_participant_keys, research_source_identities, readme, findings) + check_english_gonol_regression(repositories, research_participant_keys, human, readme, findings) if findings: for finding in findings: @@ -235,7 +252,7 @@ def main() -> int: print(f"stack consistency: fail ({len(findings)} error(s))") return 1 - print(f"stack consistency: pass ({len(repositories)} repositories, {len(research_participants)} research participant identities)") + print(f"stack consistency: pass ({len(repositories)} repositories, {len(research_participant_keys)} research participant identities)") return 0 From 759f300bfd4b7fd97bd67fd2ead154576ad71660 Mon Sep 17 00:00:00 2001 From: Erin Spencer Date: Fri, 11 Sep 2026 23:57:21 -0700 Subject: [PATCH 11/15] fix(stack): preserve psychsocio lifecycle contract wording --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 9c4b19d..51a9bc9 100644 --- a/README.md +++ b/README.md @@ -103,10 +103,10 @@ stack-local implementation. English Gonol Construction is currently a distinct stack-local research component, separated from EDCM but not independently graduated. EPAC and psychsocio metafauna are -also pre-graduation work, with EPAC further along: EPAC has an independent extracted -repository, but extraction is not graduation, so its forge research remains here until -EPAC completes its release, downstream reconsumption, and authority-transition gates. -From Photons to the Macroverse is also stack-local pre-graduation research. +currently in this pre-graduation state. EPAC is further along: it has an independent +extracted repository, but extraction is not graduation, so its forge research remains +here until EPAC completes its release, downstream reconsumption, and authority-transition +gates. From Photons to the Macroverse is also stack-local pre-graduation research. ### Make derived artifacts fresh without depending on hosted CI From 7c95852533b3cfbab9e49aaefd04880bcf34dea1 Mon Sep 17 00:00:00 2001 From: Erin Spencer Date: Fri, 11 Sep 2026 23:59:14 -0700 Subject: [PATCH 12/15] docs(stack): bind vendored stack-update skill provenance --- .agents/skills/README.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 .agents/skills/README.md diff --git a/.agents/skills/README.md b/.agents/skills/README.md new file mode 100644 index 0000000..7c03dce --- /dev/null +++ b/.agents/skills/README.md @@ -0,0 +1,12 @@ +# Vendored agent skills + +This directory contains repo-local consumed copies of canonical skills from +`The-Interdependency/skill-lib`. + +Installed subset: + +- `stack-update` — source `The-Interdependency/skill-lib@a7b95f891d2e88c62e61524dc52a2e1577c9983d`, path `stack-update/SKILL.md`, source blob `a1e914893fa047e28d039050395937a1cf6e0138`. + +Canonical doctrine remains in `skill-lib`; vendoring does not transfer authority. +Structural stack changes must follow `.agents/skills/stack-update/SKILL.md` and pass +`python tools/check_stack_consistency.py` before merge. From eaf6662d42d780d0402dd6e19859529d313ec7d9 Mon Sep 17 00:00:00 2001 From: Erin Spencer Date: Fri, 11 Sep 2026 23:59:23 -0700 Subject: [PATCH 13/15] docs(stack): record exact stack-update source identity --- .agents/skills/stack-update/PROVENANCE.json | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 .agents/skills/stack-update/PROVENANCE.json diff --git a/.agents/skills/stack-update/PROVENANCE.json b/.agents/skills/stack-update/PROVENANCE.json new file mode 100644 index 0000000..e72aff6 --- /dev/null +++ b/.agents/skills/stack-update/PROVENANCE.json @@ -0,0 +1,11 @@ +{ + "schema": "the-interdependency.vendored-skill-provenance", + "version": "1.0.0", + "skill": "stack-update", + "source_repository": "The-Interdependency/skill-lib", + "source_commit": "a7b95f891d2e88c62e61524dc52a2e1577c9983d", + "source_path": "stack-update/SKILL.md", + "source_blob_sha": "a1e914893fa047e28d039050395937a1cf6e0138", + "authority_transfer": false, + "relation": "repo-local consumed copy; canonical doctrine remains in source repository" +} From 2c99df0c8205ffe3158906a7692564623146c4c3 Mon Sep 17 00:00:00 2001 From: Erin Spencer Date: Fri, 11 Sep 2026 23:59:57 -0700 Subject: [PATCH 14/15] fix(stack): preserve exact psychsocio contract sentence --- README.md | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 51a9bc9..f9f525f 100644 --- a/README.md +++ b/README.md @@ -102,11 +102,12 @@ package/release it, then let stack consume the released project rather than a hi stack-local implementation. English Gonol Construction is currently a distinct stack-local research component, -separated from EDCM but not independently graduated. EPAC and psychsocio metafauna are -currently in this pre-graduation state. EPAC is further along: it has an independent -extracted repository, but extraction is not graduation, so its forge research remains -here until EPAC completes its release, downstream reconsumption, and authority-transition -gates. From Photons to the Macroverse is also stack-local pre-graduation research. +separated from EDCM but not independently graduated. +EPAC and psychsocio metafauna are currently in this pre-graduation state. +EPAC is further along: it has an independent extracted repository, but extraction is not +graduation, so its forge research remains here until EPAC completes its release, +downstream reconsumption, and authority-transition gates. From Photons to the Macroverse +is also stack-local pre-graduation research. ### Make derived artifacts fresh without depending on hosted CI From 8c9b79ac03f82b3ce412aba01177640cad321e57 Mon Sep 17 00:00:00 2001 From: Erin Spencer Date: Sat, 12 Sep 2026 00:00:50 -0700 Subject: [PATCH 15/15] feat(stack): verify vendored skill source identity --- tools/check_stack_consistency.py | 66 +++++++++++++++++++++++++++++++- 1 file changed, 64 insertions(+), 2 deletions(-) diff --git a/tools/check_stack_consistency.py b/tools/check_stack_consistency.py index bef29ba..fed4c38 100644 --- a/tools/check_stack_consistency.py +++ b/tools/check_stack_consistency.py @@ -2,10 +2,10 @@ # id: stack_consistency_checker # module_name: check_stack_consistency # module_kind: verification-tool -# summary: fail-closed structural consistency checks across stack manifests, research bases, authority projections, and work-graph identity +# summary: fail-closed structural consistency checks across stack manifests, research bases, authority projections, work-graph identity, and vendored-skill provenance # owner: The-Interdependency/stack # public_surface: command-line exit status and human-readable findings -# internal_surface: manifest digest, repository/base cross-checks, separated-component checks +# internal_surface: manifest digest, repository/base cross-checks, separated-component checks, vendored-skill provenance # auth_boundary: none # storage_boundary: read-only repository files # network_boundary: none @@ -43,6 +43,12 @@ # then: the project has an explicit research_participants record and the former source owner does not retain a known superseded authority claim # class: boundary # since: 2026-09-12 +# +# id: vendored_stack_skill_has_exact_source_identity +# given: stack vendors .agents/skills/stack-update/SKILL.md +# then: provenance pins an immutable skill-lib commit and source blob, authority_transfer is false, and the local Git blob identity matches the declared source blob +# class: boundary +# since: 2026-09-12 # === END CONTRACTS === """Verify stack authority/provenance projections agree. @@ -71,6 +77,9 @@ MANIFEST_PATH = ROOT / "stack-manifest.json" HUMAN_MANIFEST_PATH = ROOT / "STACK_MANIFEST.md" README_PATH = ROOT / "README.md" +SKILLS_README_PATH = ROOT / ".agents" / "skills" / "README.md" +STACK_UPDATE_SKILL_PATH = ROOT / ".agents" / "skills" / "stack-update" / "SKILL.md" +STACK_UPDATE_PROVENANCE_PATH = ROOT / ".agents" / "skills" / "stack-update" / "PROVENANCE.json" HASHED_FIELDS = ("repositories", "research_participants", "boundaries") HEX40 = re.compile(r"^[0-9a-f]{40}$") @@ -85,6 +94,11 @@ def manifest_digest(manifest: dict[str, Any]) -> str: return hashlib.sha256(encoded).hexdigest() +def git_blob_sha(data: bytes) -> str: + header = f"blob {len(data)}\0".encode("ascii") + return hashlib.sha1(header + data).hexdigest() + + def error(findings: list[str], code: str, message: str) -> None: findings.append(f"{code}: {message}") @@ -229,6 +243,53 @@ def check_english_gonol_regression( error(findings, "english_gonol.projection_missing", f"{surface_name} does not expose English Gonol's separated workspace") +def check_stack_update_skill_provenance(findings: list[str]) -> None: + if not STACK_UPDATE_SKILL_PATH.exists(): + error(findings, "skill.missing", "vendored stack-update/SKILL.md is missing") + return + if not STACK_UPDATE_PROVENANCE_PATH.exists(): + error(findings, "skill.provenance_missing", "vendored stack-update skill has no PROVENANCE.json") + return + + try: + provenance = load_json(STACK_UPDATE_PROVENANCE_PATH) + except (OSError, json.JSONDecodeError) as exc: + error(findings, "skill.provenance_invalid", f"cannot read stack-update provenance: {exc}") + return + + expected_values = { + "schema": "the-interdependency.vendored-skill-provenance", + "version": "1.0.0", + "skill": "stack-update", + "source_repository": "The-Interdependency/skill-lib", + "source_path": "stack-update/SKILL.md", + } + for field, expected in expected_values.items(): + if provenance.get(field) != expected: + error(findings, "skill.provenance_field", f"{field} must be {expected!r}, got {provenance.get(field)!r}") + + source_commit = str(provenance.get("source_commit", "")) + source_blob_sha = str(provenance.get("source_blob_sha", "")) + if not HEX40.fullmatch(source_commit): + error(findings, "skill.source_commit", f"invalid source_commit {source_commit!r}") + if not HEX40.fullmatch(source_blob_sha): + error(findings, "skill.source_blob", f"invalid source_blob_sha {source_blob_sha!r}") + if provenance.get("authority_transfer") is not False: + error(findings, "skill.authority_transfer", "vendored stack-update must keep authority_transfer=false") + + actual_blob_sha = git_blob_sha(STACK_UPDATE_SKILL_PATH.read_bytes()) + if source_blob_sha and source_blob_sha != actual_blob_sha: + error(findings, "skill.content_drift", f"vendored stack-update blob is {actual_blob_sha}, provenance pins {source_blob_sha}") + + if not SKILLS_README_PATH.exists(): + error(findings, "skill.index_missing", ".agents/skills/README.md is missing") + else: + skills_readme = SKILLS_README_PATH.read_text(encoding="utf-8") + for value in (source_commit, source_blob_sha, "The-Interdependency/skill-lib"): + if value and value not in skills_readme: + error(findings, "skill.index_drift", f".agents/skills/README.md does not carry provenance value {value!r}") + + def main() -> int: findings: list[str] = [] try: @@ -245,6 +306,7 @@ def main() -> int: research_participant_keys, research_source_identities = check_research_participants(manifest, human, findings) check_base_records(repositories, research_participant_keys, research_source_identities, readme, findings) check_english_gonol_regression(repositories, research_participant_keys, human, readme, findings) + check_stack_update_skill_provenance(findings) if findings: for finding in findings: