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
8 changes: 7 additions & 1 deletion src/docs/Frameworks/Agentic-Development/memory-template.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,10 @@ exception, made explicit rather than left as an oversight:
`pull_request_template.md` and `CODEOWNERS` review routing make no sense for a repo
where every change lands as a direct commit to `main`.
See [Memory writing rules](design.md#memory-writing-rules) for what a good direct
commit looks like.
commit looks like. This only works in practice once the organization's ruleset stops
requiring pull requests for `memory` repositories β€” see
[Repository Type Property](../../Ways-of-Working/Repository-Type-Property.md) for how
that exclusion is implemented via a `Type: Memory` custom property value.
- **No external dependencies.** Plain Markdown files have no supply chain, so
`.github/dependabot.yml` has nothing to update.
- **Small, defined audience.** `SUPPORT.md` and `CODE_OF_CONDUCT.md` exist to set
Expand All @@ -90,3 +93,6 @@ public audience, even when the adjoining `docs` repository is public.
set this page's scaffold deliberately departs from.
- [Organization Standard](../../Ways-of-Working/Organization-Standard.md) β€” how
initiative-defined, type-specific exceptions to the default file set are allowed.
- [Repository Type Property](../../Ways-of-Working/Repository-Type-Property.md) β€” how a
`Type: Memory` custom property value excludes memory repositories from the org-wide
pull-request-required ruleset so the direct-commit workflow above actually works.
1 change: 1 addition & 0 deletions src/docs/Ways-of-Working/Organization-Standard.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ Agent files are allowed when they point to, summarize, or operationalize the cen
## Where this connects

- [Repository Standard](Repository-Standard.md) β€” the repository-level contract every repository must satisfy.
- [Repository Type Property](Repository-Type-Property.md) β€” the concrete `Type` custom-property mechanism that implements "repository types" and "required custom properties, branch protection" from this page.
- [Documentation Model](Documentation-Model.md) β€” why specs own why and what, while designs own implementation.
- [Dependency Updates](../Capabilities/dependency-updates/spec.md) β€” the supply-chain update capability every repository inherits.
- [GitHub Actions](../Coding-Standards/GitHub-Actions.md) β€” workflow authoring and enforcement rules.
1 change: 1 addition & 0 deletions src/docs/Ways-of-Working/Repository-Standard.md
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,7 @@ For example, PSModule can define its module-specific managed files in `PSModule/
## Where this connects

- [Organization Standard](Organization-Standard.md) β€” what an initiative organization must define centrally.
- [Repository Type Property](Repository-Type-Property.md) β€” the `Type` custom property that classifies a repository and drives which type-specific files and controls apply.
- [README-Driven Context](Readme-Driven-Context.md) β€” why the README is the front door.
- [PR Format](PR-Format.md) β€” the PR Manager-style title and description format.
- [GitHub Actions](../Coding-Standards/GitHub-Actions.md) β€” workflow and automation standards.
Expand Down
117 changes: 117 additions & 0 deletions src/docs/Ways-of-Working/Repository-Type-Property.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
---
title: Repository Type Property
description: How a single "Type" custom property classifies every repository in an initiative organization and drives which org-wide controls apply to it.
---

# Repository Type Property

[Organization Standard](Organization-Standard.md) requires every initiative to define
"repository types used by the initiative" and "required custom properties, labels, branch
protection, and review rules." This page is the concrete mechanism that satisfies both at
once: a single GitHub organization **custom property named `Type`**, whose value per
repository determines which org-wide rulesets and controls apply.

## The pattern

Each initiative organization defines:

1. One `single_select` custom property named `Type`, required on every repository, with a
default value (typically `Other`).
2. An allowed-values list specific to that organization's actual repository shapes (a docs
org and a module-publishing org will not need the same list).
3. Org-wide rulesets (branch protection, required reviews, and similar controls) that
target repositories by their `Type` value instead of by repository name.

Setting a repository's `Type` is then the single action that determines every `Type`-scoped
control it inherits β€” no per-repository ruleset edits, no repository-name lists to keep in
sync by hand.

## Filter by exclusion, not by inclusion

When a ruleset condition targets `Type`, write it as an **exclude** list of the `Type`
values that should be exempt, with an empty `include` list β€” not an include allow-list of
the values that should be covered.

```json
"repository_property": {
"include": [],
"exclude": [{ "name": "Type", "source": "custom", "property_values": ["Memory"] }]
}
```

An empty `include` array matches every repository; the `exclude` array then subtracts
specific `Type` values. This means:

- Adding a brand-new `Type` value in the future (a new repository shape nobody has
invented yet) is covered by the ruleset automatically, with no ruleset edit required.
- Only `Type` values an administrator has explicitly named in `exclude` ever lose
coverage. Nothing falls out silently.

An include allow-list inverts this safety property: any repository whose `Type` is not on
the list silently loses coverage, including every future `Type` value nobody remembered to
add. Exclude-based conditions are the only version of this pattern that is safe to extend
over time.

## Verifying a migration before cutting over

Moving a ruleset from a name-based or single-purpose-property condition onto `Type` is a
live change to branch protection. Verify it does not silently drop coverage for any
repository before making it live:

1. Enumerate every repository in the organization and the `Type` (or prior property) value
it currently has, via `GET /orgs/{org}/properties/values`.
2. Compute, for the **current** ruleset condition, which repositories are covered.
3. Create the replacement ruleset under a temporary name so both rulesets can exist side by
side, then use `GET /repos/{owner}/{repo}/rules/branches/{branch}` per repository to
compute which repositories the **new** condition actually covers (this is more reliable
than reasoning about condition JSON by hand, since it reflects GitHub's own evaluation).
4. Diff the two coverage sets. The only differences should be the `Type` values the
migration intentionally excludes. Any other difference means the new condition is wrong.
5. Only after the diff matches expectations: delete the old ruleset, then create the final
ruleset under its real name, then delete the temporary one. This ordering means both
rulesets are briefly active together rather than there being a gap with neither active.

## A known API quirk: ruleset `PATCH` may not work

`PATCH` on `/orgs/{org}/rulesets/{id}` has been observed to fail (`404`) for tokens that
otherwise have full `GET`/`POST`/`DELETE` access to the same endpoint, including on a
disposable test ruleset created solely to isolate the failure. Treat in-place ruleset edits
as unreliable and use the delete-old / create-new sequence above instead, even for small
condition changes.

## Deprecating single-purpose properties

An initiative may have started with a narrow, single-purpose property (for example, a
`BranchStrategy` property with values like `None` / `GitHub Flow`, used only to gate one
ruleset). Once a `Type` property exists and a ruleset condition has been migrated onto it
and verified, retire the narrow property (`DELETE /orgs/{org}/properties/schema/{name}`)
rather than keeping two overlapping classification properties. `Type` is the one property
that should answer "what kind of repository is this," and every `Type`-scoped control
should read from it.

## Worked examples

Both current MSX initiative organizations use this pattern:

| Organization | `Type` allowed values | Notes |
| --- | --- | --- |
| `MSXOrg` | `Docs`, `Memory`, `VSCodeExtension`, `Other` | Introduced from scratch, replacing a prior single-purpose `BranchStrategy` property. |
| `PSModule` | `Action`, `Archive`, `Docs`, `Framework`, `FunctionApp`, `Memory`, `Module`, `Other`, `Template`, `Workflow` | `Memory` added to an existing, already-populated `Type` property; the ruleset condition changed from a repository-name allow-list (`~ALL`) to a `Type`-based exclude. |

In both organizations, repositories with `Type: Memory` β€” the
[Memory Repository Template](../Frameworks/Agentic-Development/memory-template.md)'s
no-PR, direct-commit-to-`main` repositories β€” are excluded from the org-wide pull-request-
required ruleset. That template's workflow only works because the ruleset stops matching
`Memory`-typed repositories; without this, direct pushes to a memory repository's `main`
are rejected the same as on any other repository.

## Where this connects

- [Organization Standard](Organization-Standard.md) β€” the requirement this property
implements: documented repository types and the custom properties, rulesets, and review
rules attached to them.
- [Repository Standard](Repository-Standard.md) β€” the mandatory/type-specific/
repository-specific file-set distinction that `Type` also drives over time.
- [Memory Repository Template](../Frameworks/Agentic-Development/memory-template.md) β€” the
concrete repository type whose no-PR workflow motivated excluding `Type: Memory` from the
pull-request-required ruleset in both current organizations.
1 change: 1 addition & 0 deletions src/docs/Ways-of-Working/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ This section documents the principles, processes, and norms that every contribut
| [Git Worktrees](Git-Worktrees.md) | How agentic development is implemented locally β€” a bare-clone and worktree layout for working on several things at once. |
| [Organization Standard](Organization-Standard.md) | What every initiative organization must define centrally so humans and agents share the same expectations. |
| [Repository Standard](Repository-Standard.md) | The baseline files and behaviours every repository must expose so it is understandable, secure, and maintainable. |
| [Repository Type Property](Repository-Type-Property.md) | How a single "Type" custom property classifies every repository in an initiative organization and drives which org-wide controls apply to it. |
| [Principles](Principles/index.md) | The foundational beliefs and product mindset behind every decision. |
| [Engineering Taste](Engineering-Taste.md) | The judgment that takes over when the standards run out. |
| [Goal-Setting Framework](Goal-Setting.md) | Mission, OKRs, and initiatives β€” strategy connected to delivery. |
Expand Down
1 change: 1 addition & 0 deletions src/zensical.toml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ nav = [
]},
{"Organization Standard" = "Ways-of-Working/Organization-Standard.md"},
{"Repository Standard" = "Ways-of-Working/Repository-Standard.md"},
{"Repository Type Property" = "Ways-of-Working/Repository-Type-Property.md"},
{"Principles" = [
"Ways-of-Working/Principles/index.md",
{"Purpose and Direction" = "Ways-of-Working/Principles/Purpose-and-Direction.md"},
Expand Down