Skip to content

feat(types): add owner type standards, declaration tooling and blocking release gates #204

Description

@artiphishle

Goal

Implement the shared tooling and standards for owner-local type declarations and a generated standalone @ankhorage/types distribution. Every public Owner release must be gated on immediate availability of its changed types. Renovate is downstream update automation, not the publication trigger.

Parent roadmap: ankhorage/types#1
Contracts inventory and migration: ankhorage/contracts#209

Required skills

  • Read each repository AGENTS.md and inspect .agents/skills/.
  • Load local ankhorage-project-structure, ankhorage-coding-rules, and required architecture skills. Load the applicable skill-creator skill when editing skill sources.
  • Apply the corrected Contracts and generated-Types profiles without executable CLI/feature/hexagonal scaffolding.
  • Use the roadmap coordination skill if available in the execution environment; otherwise keep explicit claims/status/evidence in the parent issue. Never invent a missing skill or claim it was loaded.
  • Conventional commits and PR titles; assign issues and PRs to artiphishle; link PRs to this issue and the parent. Only close after all linked deliverables pass and are released.
  • gpt-6-astra / High for declaration architecture, identity and release protocol; gpt-5.6-sol / High for implementation; Medium only for settled mechanical synchronization. Pause before model changes when the environment requires the user to switch.

Audited owner sources

Baseline Devtools main: b1ff41c8e45d968530d9aaa0141360b9629b6ef4, package version 1.14.6.

  • Canonical distributed structure skill: src/tools/skills/assets/ankhorage-project-structure/SKILL.md.
  • Local synchronized copy: .agents/skills/ankhorage-project-structure/SKILL.md.
  • Managed release workflow: src/tools/workflows/files/release.yml.
  • Workflow rendering/selection: src/tools/workflows/index.ts, renderWorkflowAsync.ts and related tests.
  • Existing package/skill/agents sync: src/tools/package/, src/tools/skills/, src/tools/agents/.
  • Existing self-rollout: Devtools release dispatches devtools-release to Renovate after publication. Keep that downstream standards-rollout responsibility distinct from the new pre-publication Types gate.
  • src/types/eslint-plugins.d.ts exists, but is an ambient implementation aid, not an intentional public type-distribution API.
  • Devtools AGENTS.md prescribes check-types, while package scripts expose typecheck. Correct contradictory managed instructions as part of the standards audit; do not report non-existent commands as successfully run.

Contracts #208 regression baseline

Contracts PR #208 is merged; source snapshot 8efc393 records version 17.0.0. Its semantic ownership and migration delta are tracked in Contracts #209. No Devtools implementation or Types-release requirement was completed by that merge.

Contracts #210 regression baseline

Contracts PR #210 is merged; 17f1384 records source version 18.0.0. Extend the #208 fixtures with InfraWorkloadScalarValue, the scalar-only template variant, publicBaseUrl, required ledger targets/outputs, and InfraComputeTarget moved to its independent infraTargets.ts module. Ownership and behavior acceptance remain in Contracts #209; this merge completes no Devtools rollout or release-gate work.

A. Update the complete structure/ownership policy first

  • Replace both “shared across repositories => Contracts” and “shared + serializable => Contracts” rules. Also correct the closing Utilities summary, examples, package-boundary prose and any distributed references containing the old rule.
  • Define semantic ownership: sharing is a visibility concern, serialization is a representation property, neither determines the package owner by itself.
  • Define src/types/<topic>.ts as the owner-local location for reusable/public cohesive type groups. Preserve implementation-private types locally. Avoid one-file-per-type and unrelated catch-all files.
  • Define one explicit public extraction facade, proposed src/types/public.ts, with named export type declarations only. Keep private/ambient/test types out. Map the owner ./types subpath explicitly. No generic index.ts barrel conflict with current rules.
  • Clarify distribution: @ankhorage/<owner>/types is available with the implementation; consumers needing only types use @ankhorage/types/<owner>. The latter embeds generated declarations and must not re-export from installed Owner packages.
  • Document the distinction between the only editable source (Owner) and generated distribution artifacts (Types). No manual duplicate declarations and no separate per-owner @types packages.
  • Contracts profile: only portable, genuinely shared wire/data formats, with actual producer/consumer evidence; no functions, runtime constants, methods/call signatures, framework/plugin objects, execution contexts or adapter implementations. Serializability alone does not justify a move to Contracts. Keep non-wire owner APIs at their owner, even when fully serializable.
  • Add a concrete Contracts feat: validate package-owned APM migration metadata before release #208 ownership example: InfraRuntimeAdapter belongs to Infra despite multiple consumers; InfraWorkloadValue credential references and InfraAuthzPolicyFile remain shared portable wire declarations in Contracts; their validators belong to Infra. Distinguish invocation-state independence from removal of persisted resource ledgers.
  • Contracts follows src/types/ and type-only export conventions but not executable CLI/feature/hexagonal scaffolding. Add a separate Types distribution profile; it must not invent a runtime provider or recursively aggregate itself.
  • Explain owner/runtime constants versus canonical wire unions and checked projections. Do not keep type declarations dependent on moved runtime values.
  • Explain external declarations, direct/aggregate identity, version mapping, allowed dependency DAG and forbidden self-slice imports.
  • Extend the feat: validate package-owned APM migration metadata before release #208 ownership example with feat: generate release docs after versioning and harden repository guidance #210: portable template/public-origin manifest data stays Contracts; persisted compute targets and ledger state belong to Infra. Preserve the independent target type topic so lifecycle and adapter declarations do not import each other. Serialization/persistence alone does not assign ownership.
  • Preserve reuse-first Utility rule, functional programming/immutability, one-runtime-export convention, no shared/, no legacy aliases and no sibling source imports.
  • Reconcile obsolete examples/reference files and skill versions; update canonical assets and regenerate managed copies. Do not hand-patch every consumer as the new source of truth.
  • Align AGENTS descriptions and actual validation scripts; preserve stricter applicable repository checks.
  • Add policy/asset/sync tests, generated docs and Changeset; release standards before owner migrations.

B. One Devtools-owned extraction/check capability

Public command names and structured inputs must follow existing provider conventions, with proposed commands such as ankh devtools types build and ankh devtools types check. Finalize names before exposing them; reuse current command invocation infrastructure.

  • Produce deterministic declarations from the explicit public type facade using supported compiler APIs/tooling; no regex-based TypeScript rewriting as production implementation.
  • Compare a declaration bundler against real multi-subpath/conditional exports, nominal identities and framework dependencies before selecting it. API Extractor is a candidate, not an assumed universal solution.
  • Pin/record generator/compiler/config versions. Coordinate Devtools #97: CLI compiler and compiler-API consumers may be separate lanes; do not force an unsupported compiler API.
  • Resolve the complete transitive type graph: inheritance, generics/defaults, overloads, import types, typeof, private support declarations, module augmentation, unique symbols and referenced packages.
  • Embed required Ankhorage declarations or resolve them to canonical sibling slices inside the Types artifact; no published reference to an Ankhorage implementation package.
  • Keep one canonical declaration identity for branded/nominal types. Test the existing CustomNavigatorRegistry brand, owner factory return values and direct/aggregate assignment in both directions. Do not strip brands, widen types or add casts to pass tests. If identity cannot be preserved with the proposed distribution, resolve the canonical declaration strategy before rollout.
  • Make external type dependencies explicit. In particular React Native types may require a whole external package; do not claim a zero-runtime install while silently auto-installing native peers. Use isolated per-subpath checks and an explicit external-dependency policy; do not copy or replace third-party declarations casually.
  • Keep unrelated framework types out of portable slices. No root facade that forces every consumer to typecheck every framework entrypoint.
  • Emit declaration hashes, dependencies/closure hashes and provenance. Ignore purely incidental output ordering/timestamps; detect meaningful public declaration or required dependency changes.
  • No source maps/source paths that require private repositories or unpublished sibling files to resolve declarations.
  • Package-output validation includes real npm/Bun tarball installs with the owner absent, no skipLibCheck/ambient stubs to conceal unresolved types.
  • Integrate structure/type-distribution status into managed tooling and Doctor through published APIs; no duplicate implementation in Renovate.

C. Blocking release protocol — not a post-release best effort

Required invariant:

Before an Owner version becomes available in the public registry, a compatible exact Types version containing that Owner candidate's declarations is already available and verified. If the public type payload/required dependency closure is unchanged, acknowledge the existing compatible Types version instead of publishing a no-op release.

  • Finalize the Owner version and exact candidate commit before declaration extraction. Build/pack from that immutable candidate; do not publish artifacts built before a later checkout/rebase/version change.
  • Produce a trusted candidate declaration artifact before Owner npm publication. A workflow cannot fetch the new Owner version from npm before it exists. Dependency sources used for assembly are build-only and must not leak into published Types dependencies.
  • Authenticate and validate the request against allowed owner repository/package/subpath, commit, run/artifact identity, version and hash. Reject forks, forged payloads, mutable source refs and private/unapproved exports.
  • Types repo is the single serialized writer. Merge candidate slices onto the latest committed collection; never overwrite concurrent changes from another Owner.
  • Use durable request/acknowledgement records and idempotency keys; handle queued, reordered, duplicated, canceled, timed-out and failed requests. A matching concurrency name in different repositories is not a global lock.
  • Do not assume cancel-in-progress: false makes the default Actions queue lossless. Validate queue behavior/capacity and recover dropped/canceled requests. GitHub concurrency documentation.
  • Reject stale same-owner versions overwriting newer current slices; preserve exact provenance/compatibility mapping for each release request. Keep stable/prerelease channels separate.
  • Run declaration/consumer acceptance; choose the central package's actual API semver. Do not blindly copy the Owner version or always patch. Ambiguous compatibility changes need explicit review and block the Owner release.
  • Publish Types through the trusted owning workflow and verify registry availability/integrity. A successful dispatch or accepted workflow run is not publication acknowledgement.
  • Owner waits for the acknowledgement matching its exact candidate hash/version/channel; timeout/failure blocks publication.
  • On success, publish the exact prepared Owner candidate and finalize tags/GitHub release. Verify at the registry, not just GitHub release metadata.
  • Resume idempotently if Types published but Owner failed, Owner published but tag finalization failed, or a rerun starts with no pending Changeset. Never depend only on a newly computed versioned=true.
  • Prevent Types self-trigger loops and generator/devtools bootstrap cycles. Use a released compatible generator, with an explicit tested protocol upgrade sequence.
  • Keep Types publication credentials in the Types release workflow; Owner jobs do not need global npm publish credentials. Use scoped approved GitHub/OIDC permissions. Permission/configuration changes needing human action are explicit blockers, not bypasses.
  • Scope rollout so unregistered owners are not accidentally deadlocked during bootstrap. Once a package is onboarded, the gate is mandatory; remove any rollout-only bypass when coverage is complete.

Current managed workflow builds before Version packages directly on main, then checks out/rebases main and publishes. Audit/fix candidate ordering as part of this protocol; merely inserting a dispatch before the existing publish step is insufficient.

D. Test matrix

  • Identical declarations => no Types release; new Owner version mapped to existing Types payload.

  • Added/removed/changed public type and transitive dependency change => correct release decision.

  • Two different owners and multiple same-owner candidates concurrently => no lost update/regression.

  • Duplicate/out-of-order request and queue replacement/capacity => recoverable, no silent publish.

  • Types publication failure/registry lag => Owner remains unpublished.

  • Types succeeds, Owner fails => exact retry without duplicate Types publication.

  • Rerun with no Changeset and already-published package => correct resume/finalization.

  • Stable/prerelease isolation and source-provenance tampering rejection.

  • No self-aggregation or infinite owner <-> types <-> devtools release loop.

  • Headless consumer, React/RN owner, branded Navigator API and a generic Infra adapter.

  • Use Contracts feat: validate package-owned APM migration metadata before release #208 as an extraction/diff regression fixture: the required InfraRuntimeDesiredState<P> parameter in status/suspend/destroy, the credential discriminant/reference/key and the optional Cerbos policy list must survive generation. Compare parameter tuples and wire unions through direct and aggregate exports; declaration changes must trigger the release decision even when symbol names and import paths are unchanged. Preserve independent destroy-request typing. Actual fresh-invocation and credential/policy validation behavior is verified at Infra/provider owners under Contracts feat: validate packed APM owner releases #209.

  • Owner absent during install/typecheck; external types policy accurately reflected.

  • Repeat sync/build byte-stable; packaging, lint, Knip and docs unaffected.

  • Add feat: generate release docs after versioning and harden repository guidance #210 declaration/closure regression fixtures: preserve scalar-only template segments, optional public-base-URL metadata, required readonly ledger targets/outputs, and the independent target module without unresolved owner imports or cycles. Verify public API/type changes trigger publication; a source-file-only relocation with identical public declaration/dependency semantics must not force a Types release. Keep runtime validation guarantees (non-empty template, canonical URL, safe persistence/materialization) separate from what TypeScript declarations enforce; behavior tests belong to Infra/provider owners.

Delivery gates

Split implementation into reviewable PRs: standards/profile correction; extraction/validation; release protocol; managed rollout/Doctor integration. Link all to this issue rather than creating unbounded duplicate phase issues.

Run actual repository scripts and the mandated validation order; resolve the AGENTS/script mismatch first. No changes to production infrastructure, secret values, existing branch protections or repository permissions are authorized by this planning issue alone.

Done only when the released Devtools version supports the protocol, Types and pilot owners prove the gate, and the parent roadmap records the complete rollout. Renovate may update consumer versions afterwards; it cannot become the delayed source of truth for type availability.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions