A record from the Factory repository, docs/service-access-organisation-receipt.json, shown as committed except that its local paths appear as placeholders in angle brackets, such as <local evidence archive>, standing for files that are not published; a placeholder that stands in for a key keeps the file's name, as in <local evidence file: report.md>. Every hash, date and count is as recorded. The build review says what the Factory's receipts support.
{
"recordedAt": "2026-09-30T05:10:00+00:00",
"base": "c044d5b",
"branch": "factory/churn-p7",
"disposition": "implemented-awaiting-independent-review",
"scope": "Service access, SA1-F2 (Fable 5.1 interim round 1, finding 2), fixed per the coordinator's review of the first submission (<local evidence archive>, findings 1-9): an absent repository owner type is unknown, never taken for \"user\" (rule 1); a repository the organisation owns, or whose owner type is not recorded, carries that gap through discoverServices, declaredPresence and the Counts, unless a conclusive organization-scope listing rules a name out; a conclusive organisation listing that lists the name still leaves the reference unknown (organisation-unlisted, redefined to also mean the name's visibility to this repository is not settled); absence is as old as the oldest listing it rests on, the organisation listing included; a discovery's listings are rechecked against the input's repository including its owner type, and a user-owned repository takes no organization-scope listing; a binding that carries an owner type requires the input's to match exactly, an absent input owner type against it is refused INVALID, and a binding with none accepts the input's owner type as evidence without defaulting either side. Additive only: ownerType is optional on Repository and on the github-repository StoreBinding; its absence is read exactly as stored and never reinterpreted, in either direction.",
"describes": "src/service-discovery.ts and src/service-access.ts, amending them as first recorded in docs/service-access-receipt.json",
"specification": "<local evidence archive> section 3 and section 5 step 5, amended a third time for Fable round 1 finding 5 (each bare \"(finding N)\" now names churn/wave-1/P7/coordinator-review.md; its three prose em dashes are replaced; one sentence records the referencedNotStored fix, Fable round 1 finding 2). The text amended for the coordinator's review is preserved at service-access-spec.r7.md (byte-identical to the round-1 receipt's .md hash below); the packet's first, rejected draft remains at service-access-spec.r6.md, and the pre-amendment text at service-access-spec.r5.md, beside it.",
"implementer": "This revision (round 2, fixing Astra and Fable round 1's findings): Claude Sonnet 5 (claude-sonnet-5), delegated per <local evidence archive> churn automation (\"Implementation here is by Claude Sonnet only\"), read-only orchestration by Opus 5.5 elsewhere. Round 1 (the coordinator-review.md fix): Claude Sonnet 5 (claude-sonnet-5) fixing packet P7 of <local evidence archive> (id P7, packets.json) per the coordinator's review; the packet commissions Claude Sonnet 5.5, and no record in this archive establishes that a 5.5 session, rather than 5, actually ran either round; recorded here as each session reported itself, per Fable round 1 finding 6(a).",
"stability": "The stored shapes are unchanged: sf-service-access/1 and sf-service-access-bindings/1 carry no protocol revision, since ownerType is an optional, additive field every reader reads back exactly as stored (see the spec amendment's closing paragraph of section 3). A document stored before this change round-trips with no ownerType key at all, not a defaulted one, and its absence is now read as unknown rather than \"user\" wherever that matters to a decision (P7-A6, coordinator finding 1(a)).",
"tests": {
"files": {
"test/service-kinds.test.ts": 4,
"test/service-discovery.test.ts": 23,
"test/service-access.test.ts": 23,
"test/service-access-canaries.test.ts": 2,
"test/service-access-boundaries.test.ts": 3,
"test/service-access-adversarial.test.ts": 14,
"test/service-access-regressions.test.ts": 14,
"test/service-access-organisation.test.ts": 14
},
"existingTestsChanged": "test/service-access-organisation.test.ts, within this packet's own suite: the first P7-A6 test builds its legacy binding and repository as literals with no ownerType key (round 1, finding 1's fixture fix); the coordinator finding 5 test gained one assertion that view.counts!.secrets.referencedNotStored.state is never \"exact\" while the consumed name's organisation level is unsettled (round 2, Fable round 1 finding 2); the P7-A4, P7-A5 and coordinator finding 1(b) tests now bind TALLY_USER_BINDING rather than TALLY_BINDING (round 2, Fable round 1 finding 3). test/helpers/service-access.ts: TALLY carries ownerType: \"user\" explicitly; TALLY_BINDING is restored to its pre-revision shape (no ownerType key) so it no longer changes test/service-access.test.ts's replay behaviour, and the new TALLY_USER_BINDING carries ownerType: \"user\" explicitly for the tests that need it (round 2, Fable round 1 finding 3, verified first on a scratchpad copy: fable-r1-fixture-experiment.diff). tallyListings() gained an optional repository parameter (additive, every existing call site unaffected). No file outside this packet's own suite was changed, at either round.",
"new": {
"suite": "test/service-access-organisation.test.ts",
"tests": 14,
"acceptance": "P7-A2 through P7-A6 (unchanged in substance), plus 7 tests added for the coordinator review's findings 1(a-c), 2, 3, 4 and 5; P7-A1 is the spec amendment and its record below; P7-A7 and P7-A8 are the full and focused runs recorded under verification"
}
},
"acceptance": "implemented, awaiting independent review (round 2): round 1 fixed the coordinator's ten findings but Astra round 1 (astra-r1.md) and Fable round 1 (fable-r1.md) both failed it: Astra's finding 1 and Fable's finding 2 on the countSet organisation-unsettled gap (both against the committed HEAD 87f86fd), Fable's finding 3 on the one inherited test failure (working tree only), and Fable's finding 5 on the spec's wording. This revision fixes the countSet gap (src/service-discovery.ts, orgUnsettled in countSet), restores the inherited test to a pass (test/helpers/service-access.ts, test/service-access-organisation.test.ts), and fixes the spec wording (service-access-spec.md, service-access-spec.r7.md preserving the pre-fix text). A fresh Fable 5.1 (max) and Astra (gpt-6-astra, high) review, read-only, per <local evidence archive>, must both pass before this packet merges (after astra-sweep-sa lands, per packets.json mergeNotes).",
"review": {
"rounds": [
{
"reviewer": "coordinator",
"round": 1,
"verdict": "FAIL",
"report": "<local evidence archive>",
"findings": 10,
"disposition": "all ten fixed in round 1 of this revision; see scope, stability and limits above and below"
},
{
"reviewer": "astra",
"round": 1,
"verdict": "FAIL",
"report": "<local evidence archive>",
"findings": 6,
"disposition": "findings 2-5 (declaredPresence, stale organisation evidence, listing owner identity, missing-owner-type-as-user) were already fixed by round 1 of this revision, before this report; finding 1 (countSet exact zero) is fixed in this round; finding 6 (P7-A8, no clean npm run check) is addressed under verification below"
},
{
"reviewer": "fable",
"round": 1,
"verdict": "FAIL",
"report": "<local evidence archive>",
"findings": 8,
"disposition": "finding 1 (HEAD is the rejected first submission) is moot once this commit supersedes it; finding 2 (countSet exact zero) and finding 3 (inherited test failure) are fixed in this round; finding 4 (P7-A8) is addressed under verification below; finding 5 (spec wording) is fixed in this round; findings 6-8 (receipt and ledger text, minor) are addressed in this receipt where they concern this file"
}
]
},
"verification": {
"strictTypecheck": "passed (npx tsc --project tsconfig.json, exit 0)",
"focused": {
"tests": 97,
"pass": 97,
"fail": 0,
"cancelled": 0,
"skipped": 0,
"todo": 0,
"command": "node --test test/service-access.test.ts test/service-access-adversarial.test.ts test/service-access-boundaries.test.ts test/service-access-canaries.test.ts test/service-access-regressions.test.ts test/service-discovery.test.ts test/service-kinds.test.ts test/service-access-organisation.test.ts",
"note": "round 1's known failure (test/service-access.test.ts acceptance 4, TALLY_BINDING replay) is resolved by restoring TALLY_BINDING to its pre-revision shape (Fable round 1 finding 3); test/service-access.test.ts itself is unmodified"
},
"full": {
"command": "npm run check",
"note": "Historical round-1 full run:1250 tests,1246 passed,3 failed,1 cancelled. One replay failure was caused by the changed TALLY_BINDING helper, even though the failing test file itself was unchanged. Restoring that fixture resolves it. This revision still needs a serial full check; see service-access-organisation-followup-receipt.json."
}
},
"limits": [
"Test-made fixtures only, as increment 1 already was: no reader for gh repo view --json owner or an organization-scope listing (gh secret/variable list --org) is built in this repository; TALLY_ORG and its listings are placeholders the test wrote (test/helpers/service-access.ts)",
"A conclusive organization-scope listing that has the name is still not resolved to present for the repository- or environment-scoped consumed reference: it stays unknown: organisation-unlisted, now on the corrected ground that the name's visibility to this repository (all, private or selected repositories) is not read, rather than the earlier and wrong \"the fold does not yet merge presence across scopes\" (coordinator finding 5); still open, narrower than SA1-F2: no acceptance criterion exercises resolving it to present, and rule 1 makes unknown the safe default",
"The organisation-scope check applies to github-secret and github-variable locations at repository or environment scope only, mirroring the existing dependabot exclusion from stored-not-referenced; dependabot-scope secrets are unchanged by this packet",
"Service access increment 1 stays provisionally accepted with Astra's sweep (astra-sweep-sa) in review; this packet does not change that status and this receipt does not supersede docs/service-access-receipt.json",
"The 1000-line astra-sweep-sa lane's scanner regions of src/service-discovery.ts (main lines 436-1972) were not touched, consistent with packets.json forbiddenPaths; this packet's changes sit at UNKNOWN_REASONS (line ~120), Scope/Repository/repositoryOf/scopeOf (~2003-2075), parseDiscoveryInput (~2500), the presence loop and countSet (~2830-2960) of src/service-discovery.ts, and StoreBinding/bindingOf/#requireRepository/declaredPresence of src/service-access.ts",
"P7-A8 (a clean npm run check for this revision) is not yet established; see verification.full",
"This receipt's round-2 text is written by this lane, not the coordinator; the ledger text the coordinator owns (docs/build-review.md, docs/agents/service-access.md, docs/guide/service-access.md, docs/agents/factory-model.md, all outside allowedPaths) is unchanged by this revision and still reflects round 1 only, per <local evidence archive>"
],
"evidenceSha256": {
"src/service-discovery.ts": "9435cba90ad2c9a42a926747e876e5c9c98fad2fc89ad4b7bcda1e78495607e5",
"src/service-access.ts": "b321daa51bbeb33bd1b73727b95115a184899e336f8d8f675c130bb992637bb9",
"test/helpers/service-access.ts": "8383a8e8af1590514dd00a6e935c7cfb8cdc29242a6efa92987c676c3abee6d4",
"test/service-access-organisation.test.ts": "db4724e28c6599b0ed504c4de682c326ccfaf7232423426f7b63c5b25a64cb07",
"<local evidence archive: service-access-spec.md>": "cc88a6ae46e93c47f729473e342cdacff9e45f058d9b844219c48a5a352457ef",
"<local evidence archive: service-access-spec.r5.md>": "87eb5123176bfbd28bf2d95a5e52c0d15eab0b00d93d6ca9eab855870981046e",
"<local evidence archive: service-access-spec.r6.md>": "e76648da9eed4660e5bd5ee1bdf028a24d06778ff3e0f96f1cac64cb155393d7",
"<local evidence archive: service-access-spec.r7.md>": "6fa24f9b331e469a559db15a9e904bf2ccaaef260b3bef117f9e1e764067e4d7"
}
}
