Open source · Microsoft 365

M365 Governance as Code

An open source Microsoft 365 assessment engine that shows what it observed, why it reached a conclusion, and what it could not establish.

Or have it run for you: a fixed-scope assessment, delivered as documents you keep and can verify without us.

Engine
1.0.0b8@2d4f5db76f21
Rules published
22
Licence
MIT
  1. 01
    SourcesThe tenant, as Microsoft exposes it.
    Your tenant
  2. 02
    Read-only collectorsObserve. Delegated or application, recorded either way.
    Engine
  3. 03
    Canonical evidenceWhat was seen, when, by which version, under which identity.
    Engine
  4. 04
    Explicit rulesVersioned files, each stating the basis on which it judges.
    Engine
  5. 05
    Run / RunSetOne evaluation, and the set it belonged to.
    Engine
  6. 06
    AssessmentThe document. Declares its contract and carries its own evidence.
    Artefact
  7. 07
    Comparison · WorkbenchReads Assessments. Transports the conclusion; never recomputes it.
    Consumer

A rule result explained

Produced by the Engine at revision 2d4f5db7, from the fixture list-over-limit.json. Nothing on this page is typed by hand: change the fixture and this section changes with it.

What was checked

Resource
contoso,list,archive (list)
Rule
SPO-LIST-001 v2.0
Question
A list or library past 100,000 items can no longer have its permission inheritance broken
Schema
1.0

What the Engine observed

  • items.countobserved148000
  • permissions.inheritance_brokenobservedfalse

Coverage requested items, permissions; completed items, permissions; nothing was unavailable.

What the Engine concluded

fail

The list holds 148000 items, above Microsoft's documented limit of 100,000, and still inherits its permissions. Inheritance can no longer be broken on this list, so it cannot be given unique permissions later.

The Engine's own words, in English

Basis: documented-limit, a boundary the product imposes, which is why this can be stated as a fact rather than a preference. Severity medium is how much it matters, not how much attention it deserves; they are different questions.

The full reading: how it was established, what it does not prove, and what to do next

What this does not prove

A list holding 99,000 items and growing passes this rule today and loses the ability permanently within weeks, without anything in the report changing to warn about it. The rule measures a position, not a trajectory, and the boundary it describes is the one place where being close to a limit matters more than being past it: once crossed, the option does not come back. Every pass here means "not yet", never "safe".

The Engine's own words, in English

What you can do next

Microsoft's guidance is preventive, not corrective: "share large folders before they hit 100,000 items". For a container already past the limit, reducing the count does not restore the ability in every case, and the supported route is to restructure the content across containers that stay below it. Decide whether this container will ever need unique permissions before restructuring, because if the answer is no, no action is required.

The Engine's own words, in English

What this example represents

Collected
2026-08-05T14:02:11Z
Collector
spo-collector 0.1.0
Source
SharePoint Online · PnP.PowerShell / CSOM
Identity
application, scopes Sites.Read.All
Tenant
contoso.sharepoint.com

A fixture that ships with the Engine, not a tenant that was read. The host, the timestamp and the identity below belong to the simulated document. What is real is the result: the Engine produced it from this evidence, at the revision above.

Where it lives in an Assessment

Text
Assessment
├── canonical
│   ├── manifest
│   ├── RunSet   ← the Run above is one of these
│   ├── evidence
│   ├── versions
│   └── hashes
└── derived
    └── reports

Canonical content is archived and verified; reports are regenerated from it. The assessment_id derives from the canonical digests, so an Assessment that changed is a different Assessment. A Comparison references two of them and never embeds or mutates either.

  1. Evidencewhat the collector observed
  2. Rulethe versioned statement that interprets specific evidence paths
  3. Resultone rule applied to one resource
  4. Runall applicable rule results for one resource
  5. RunSetthe tenant-scale collection of runs
  6. Assessmentthe verifiable package a customer archives, opens and compares

A result is not an Assessment. It is one conclusion inside one Run, inside a RunSet carried by an Assessment.

The result as the Engine wrote it
JSON
{
  "rule_id": "SPO-LIST-001",
  "title": "A list or library past 100,000 items can no longer have its permission inheritance broken",
  "rule_version": "2.0",
  "schema_version": "1.0",
  "resource": {
    "workload": "sharepoint",
    "type": "list",
    "native_id": "contoso,list,archive"
  },
  "outcome": "fail",
  "message": "The list holds 148000 items, above Microsoft's documented limit of 100,000, and still inherits its permissions. Inheritance can no longer be broken on this list, so it cannot be given unique permissions later.",
  "basis": "documented-limit",
  "severity": "medium",
  "evidence_used": [
    {
      "path": "items.count",
      "state": "observed",
      "value": 148000,
      "lower_bound": null,
      "upper_bound": null,
      "detail": null
    },
    {
      "path": "permissions.inheritance_broken",
      "state": "observed",
      "value": false,
      "lower_bound": null,
      "upper_bound": null,
      "detail": null
    }
  ],
  "passes_without_resolving": "A list holding 99,000 items and growing passes this rule today and loses the ability permanently within weeks, without anything in the report changing to warn about it. The rule measures a position, not a trajectory, and the boundary it describes is the one place where being close to a limit matters more than being past it: once crossed, the option does not come back. Every pass here means \"not yet\", never \"safe\".",
  "sources": [
    {
      "url": "https://learn.microsoft.com/office365/servicedescriptions/sharepoint-online-service-description/sharepoint-online-limits",
      "title": "SharePoint limits, Items in lists and libraries",
      "publisher": "Microsoft",
      "checked_at": "2026-08-05"
    },
    {
      "url": "https://learn.microsoft.com/sharepoint/manage-permission-scope",
      "title": "Manage Permission Scopes in SharePoint",
      "publisher": "Microsoft",
      "checked_at": "2026-08-05"
    }
  ],
  "remediation": "Microsoft's guidance is preventive, not corrective: \"share large folders before they hit 100,000 items\". For a container already past the limit, reducing the count does not restore the ability in every case, and the supported route is to restructure the content across containers that stay below it. Decide whether this container will ever need unique permissions before restructuring, because if the answer is no, no action is required.",
  "message_degraded": false,
  "engine_detail": "",
  "attention": {
    "state": "act",
    "rank": 0,
    "because": [
      "the rule failed against a documented-limit, which the vendor documents"
    ]
  }
}

Four different sentences, rendered identically

A green box cannot tell you which of these it means, and they lead to four different budgets. Every rule in the Engine states its basis, and only the two normative ones can ever reach act.

BasisWhat it licenses the tool to sayNormativeRules today
RequirementThe product enforces it. There is no alternative configuration.yes0
Documented limitMicrosoft documents a boundary, and the number is published.yes2
Documented guidanceMicrosoft recommends it and permits the other option.no8
ConventionWe think it is a good idea. A reasonable organisation may decline.no12

Of the 22 published rules, 16 have a shipped collection profile and 6 do not. A rule that cannot be collected says so; it does not quietly pass.

What you just read

The result above is not an illustration. It is produced by the engine from packaged evidence, re-rendered every time this page is built, and it carries four lines that most reports do not have together: what was observed, on what basis, how complete the evidence was, and what the conclusion does not establish.

That last line is why the first three are worth acting on.

Why this is different

It shows why. Every conclusion names its basis: a requirement the product enforces, a documented limit with a number, Microsoft's own guidance, a convention, or an opinion stated as ours. Four of those lead to four different conversations, and a report that renders them identically has removed the one thing the reader needed. The five kinds of claim →

Unknown stays unknown. When evidence was not collected, was refused, or cannot answer the question, the result does not become a pass. It says so, in words, and the report distinguishes what was observed from what was assumed. Why unknown is never a pass →

The evidence is yours. Collection, assessment and reporting run on your machine. The documents that come out can be inspected, re-run and verified by somebody else without us. Checking a document somebody handed you →

How it works

Four steps, and you can stop after any of them and still have something usable.

1 · Microsoft 365A read only collector reads the surfaces you point it at, with credentials you configure
2 · EvidenceWhat came back, normalised to JSON, with its provenance and the gaps named
3 · RulesPublic rule files, in plain text, that you can read, argue with and change
4 · AssessmentA document for a person in Markdown and for a pipeline in JSON

The architecture in full →

What it can assess

Thirteen collection areas. Nine feed rules; four deliberately do not, because a conclusion needs a sentence somebody can defend and Microsoft publishes nothing to defend one with.

SharePoint sites and storageOwnership, quota, classification, sharing and permission scale
Custom script and customisationWhether the classic scripting model is still open, and what that permits
Conditional AccessWhether a policy that appears in the portal is enforcing anything
Copilot agentsWhat exists, published as an inventory rather than as a verdict
Microsoft 365 licensingAssignment, usage and dependency kept separate, so an unused licence is not read as a saving before the consequence is established

Every capability, and how far each has been proved →

Try it

It ships with example data, so the whole thing runs before it is pointed at anything real.

Install and run it →

Trust and security

Runs locally. Read only. No account with pH7x Systems. It has no write path to your tenant, no destination of ours to upload to, and no service we operate in its path. What it talks to is Microsoft. If the sign in is interactive, the report says so on its first page: that run saw what one person can see.

The trust model →

Open source

MIT. The rules, the collector, the schemas and the tests are public, and the result is verifiable without us.

On GitHub → · Documentation →

If you would rather not do it alone

We can run the reading with you and tell you which findings matter in your context. It answers a different question from the SharePoint Compass, which helps you choose a direction rather than measure a condition.