🏭 Complete the software-factory contract above PR #630 - #736

Open
minkimcello wants to merge 5 commits into
taras:codex/github-actions-software-factory-architecturefrom
minkimcello:claude/710-software-factory-contract
Open

🏭 Complete the software-factory contract above PR #630#736
minkimcello wants to merge 5 commits into
taras:codex/github-actions-software-factory-architecturefrom
minkimcello:claude/710-software-factory-contract

Conversation

@minkimcello

Copy link
Copy Markdown

Why

Closes#710.

The implementation stories under #633 need one decision-complete software-factory contract before they can build provider, ingress, Git, evidence, and factory behavior without choosing architecture independently. This PR completes that contract on top of the draft architecture in #630.

What changes

Before:

The draft architecture left deployment ownership, conflict behavior, durable identity, authority, target publication, replay, and terminal outcomes incomplete or distributed across documents.

After:

The architecture and specifications define the Cloudflare Durable Object owner, connection-scoped executor acquisition, GitHub intake and permission boundaries, stable run and effect identities, exact Git and target-publication behavior, machine waits, reconciliation, replay, abandonment, and the public construct inventory consumed by F1–F6.

How it works

GitHub intake and Actions execution → one durable run owner → provider-neutral effects and retained lifecycle → exact terminal reconciliation

Review guide

Start with:specs/github-actions-software-factory-spec.md

Then review:

  1. architecture.md for topology, principals, ownership, and durable boundaries.
  2. specs/workflow-spec.md for provider-neutral lifecycle and host contracts.
  3. specs/workflow-workspace-spec.md for effect, wait, reconciliation, and replay semantics.
  4. specs/executable-mdx-spec.md for the frozen conformance inventory.

Look carefully at:

  • The separation between typed-answer suspensions and provider-state machine waits.
  • Connection-scoped executor authority and transaction ownership.
  • Idempotency, attempt-state ambiguity, and completed replay without external-provider attachment.

What must stay true

  • One Durable Object owns one run's durable state; ephemeral runners own Git, evidence processes, and Agent clients.
  • Every protected mutation validates the live acquisition and expected Workspace root in its transaction.
  • External effects reconcile through their specified natural keys and fail closed on ambiguous attempted creation.
  • Completed replay reads only the durable owner and performs no external effect again.

How to verify it

Scope

Included

Intentionally unchanged

Risks and limitations

  • This PR is stacked on PR 🏭 Specify the GitHub Actions-hosted AI software factory #630. Descendant implementation branches must use accepted commit 817d3dd36cb07fddd972c6ae33716444f3cb75da as their exact contract base and be reconciled if that contract changes.
  • Recovery: amend this contract explicitly and restack affected descendants; do not repair structural omissions privately in an implementation PR.

Scope confirmation

  • Every changed file supports the purpose described above.
  • Unrelated cleanup and formatting changes are excluded.
  • Generated or mechanical changes are clearly identified.
  • The description matches the final diff and test results.

minkimcelloand others added 5 commits September 2, 2026 09:33
Turn PR taras#630's draft into a decision-complete first-release architecture. No
product, deployment, authority, identity, ownership, failure, replay, public
form, permission or ordering decision is left for a later Implementor.
The factory specification now settles: the canonical `github-issue-v1` run-ID
derivation and unsupported issue-transfer drift; `User` as the only Stage 1
spelling; the deployment topology of one SQLite-backed Cloudflare Durable
Object, an authenticated executor WebSocket, an ephemeral Actions runner and a
dedicated GitHub App; authenticated ingress order, bounded intake, dispatch
payload and OIDC claims; the exact App permissions, host ceilings, human
permission floor and `.github/workflows/**` denial; suspend-on-every-conflict
as the single Stage 4 profile; the Stage 7 trusted merge, `Git.PublishTarget`
compare-and-swap and remote-effect-before-terminal ordering; and the exact
public contract inventory. Section 8's remaining material decisions are gone.
architecture.md gains the terminology, the remote storage and executor
topology, the delivery-plane generalization, the Project-provider boundary,
comments/readiness/closure, ordered merge, target publication, trusted evidence
execution, terminal settlement, the split trusted host, and ten construct
inventory rows marked "specified by taras#710; implementation unbuilt".
The workflow and Workspace specifications gain the remote host, the executor
connection, which requests need it and which do not, the host-derived public
run ID, and provider-neutral contracts for `Git.Merge`, `Git.PublishTarget`,
`PullRequest.Comment`/`Ready`/`Close`, `Issue.Comment`/`Close`, `Evidence.Run`
and `Project.Status` — none of them reachable by an Agent or generated XMD,
whose write table stays exactly `File:write`, `Dir` and `File.Delete`. The
executable-MDX specification gains the exact authored forms and the frozen
WRH/WGI/WGE/WGM/WER/WFP/WFL acceptance tiers.
Documentation only: no production code, workflow YAML, dependency, generated
artifact or executable fixture changes, and the ownership SVG already agrees
with the amended text.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SP9dEis51dcwBnwdaXZQAg
Answer the Architect's three blocking findings on 86a4694. The public contracts
are now closed shapes rather than descriptions of shapes, run identity has one
spelling, and the two terminal paths are separate everywhere.
Finding 1 — exact bindings and durable records. specs/workflow-workspace-spec.md
is the normative schema location for every authored construct: §7.8 defines the
`GitMergeResult` clean/conflicted union, the conflict-entry record, its sorting,
duplicate and missing-side rules, and restoration failure; §7.9 defines the
`Git.PublishTarget` request and result with five exhaustive pre-states; §7.10
defines the comment request/result and how an engine-derived effect identity is
made remotely observable without using body text, plus literal `Ready`/`Close`
bindings; §10.3 does the same for `Issue.Comment` and `Issue.Close`; §10.5
settles `Evidence.Run` — the whole list runs, separate bounded stdout and stderr
with stated truncation, and an explicit table of which cases bind, which fail
and which commit nothing, with cancellation and teardown precedence fixed; §10.6
defines `Project.Status`. The factory specification §11.2 defines the versioned
closed factory protocol schemas — subject, stage, revision, handoff, actor,
outcome, invalidation, verdicts, conflict suspension, Stage 7 decisions, the
frontier and its complete reduction table, and the two asymmetric terminals.
Finding 1 also adds `PullRequest.Merged` (§7.11), the reconciled Git-host
observation that owns the post-publication merged fact, and settles the remote
host boundary (§13.2): the existing four-method `WorkflowHost` stays the host
assembly contract with a Cloudflare implementation beside the Deno one, the
runner-to-owner transport is a closed versioned envelope that refuses rather
than adapts, and an ownership table says which side owns each concern.
Finding 2 — every restatement of the run-ID derivation now uses `canonical
GitHub authority` byte for byte; the undefined Issue-provider spelling is gone.
Finding 3 — architecture.md and the factory specification now state the merged
and abandoned paths as separate ordered step lists, and the terminal record's
two shapes differ exactly as the paths do, so neither can be read as requiring
the other's effects.
Inventories, evidence tiers and the acceptance checklist are reconciled with all
of it. Documentation only; the ownership SVG is untouched.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SP9dEis51dcwBnwdaXZQAg
Apply rulings A-K from the Architect's answers on 80884f9.
A. Keep the four-method `WorkflowHost` and add that its transition and request
types — `WorkflowExecutionTransitions`, `WorkflowBeginRequest`,
`WorkflowExecutionBegun`, `WorkflowForkRequest`, `WorkflowForkSelection`,
`WorkflowRunCreation` — are provider-neutral and become package-root public
types, with runtime-named entrypoints keeping implementations and retained
encodings. Recorded as authorized future export work, not performed here.
B. `Evidence.Run` becomes an ordered fail-fast pipeline binding the executed
prefix: `{ completion, authoredCommands, executed, runTimeout? }`, rows carrying
`limit` for whichever of the two host-owned ceilings fired, a `runTimeout`
record for a whole-run expiry between commands rather than a fabricated argv
row, timeouts as ordinary unsuccessful outcomes, and fixed precedence —
cancellation over everything, first infrastructure failure authoritative with a
later teardown failure as secondary evidence, teardown authoritative alone —
with bounded diagnostic evidence retained on a failed effect's Error.
C. A comment provider must support a stable opaque correlation marker or refuse
before its first mutation. The authored logical body is preserved byte for byte
and the correlation representation rides outside it. Absence is now judged
against attempt state: no marker after an attempted-but-uncommitted creation is
permanent ambiguity, not proven absence.
D. `PullRequest.Merged` splits still-open (temporary unavailability) from
closed-unmerged (conflict), and the factory gains §10.4 — a bounded
host-configured retry, then a durable machine wait with its own protocol record,
woken by intake or an explicit resume and carrying no verdict.
E. A configured total bijection between the nine stages and nine exact Project
status option IDs, validated against a complete reread and refusing before any
intake, token, run or projection.
F. `Git.Merge`'s `purpose` is validated authorization against the
provider-authenticated merge ceiling, not write-only provenance.
G. The `RunnerRequest` envelope is deleted. The runner and owner ship as one
release identity checked by build fingerprint at admission; the messages are
private, while the owner-side authority invariants stay public and exact.
H. `FactoryTerminal` keeps journal event references, with cross-path, kind,
completeness and agreement validation spelled out.
I. The factory protocol schemas stay in the factory specification §11.2; the
other four documents link rather than duplicate.
J/K. Mixed wrapping left alone, new prose unwrapped; the tenth construct is
reflected everywhere.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SP9dEis51dcwBnwdaXZQAg
taras#710)
Ruling C asked for the comment contracts, the architecture, the WGE evidence and
the generic external-effect explanation to agree. The first three landed in
0d08dcc; §10.2 did not.
Split the two kinds of reconciled effect where the difference actually lives.
An effect that mutates a subject already there — Push, a numbered pull-request
update, ready, close, issue close, Project status — reads that subject, and a
complete observation is decisive whether or not the effect has attempted
anything. An effect that creates a new object the host names has nothing
pre-existing to read and no client-supplied idempotency key, so its completion
is visible only through a correlation value it wrote itself, and absence means a
different thing before and after a mutation has been attempted.
Only the second kind carries attempt state, and it narrows the decision in one
place: unattempted with nothing found performs once, while attempted with no
committed completion and nothing found is permanent ambiguity rather than
absence. A provider that cannot write, preserve and completely query such a
value refuses the effect from observation.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SP9dEis51dcwBnwdaXZQAg
Four narrow corrections from the Architect's verdict on b364b98.
1. The merged-observation wait is not a typed-answer suspension. A machine wait
is a second durable wait kind inside the existing lifecycle: it asks nobody
anything and ends because a later execution observed a provider again, so it
has no response schema, no `xmd workflow answer` route, no form and no bound
value, and it publishes no `suspension_request` and consumes no
`suspension_answer`. It shares only the atomic boundary — its `machine_wait`
event and the `suspended` status commit together, and the acquisition is
released after that commit. Its identity is a `waitId`, never a suspension ID;
`MergedObservationWait.suspensionId` becomes `waitId`, while
`ConflictSuspension.suspensionId` and the typed-answer protocol are untouched.
A new `MergedObservationWake` names the same `waitId` and a closed `source`,
with `intakeId` required exactly for a provider intake and absent exactly for
an operator resume. Waking is permission to look again: the intake retains a
bounded notification carrying no answer, verdict, stage, transition or
observation result, a later executor consumes it and appends the wake event in
one transaction, and a resume without a pending wake or operator authority
reports the same wait and settles suspended again.
2. The generic create-effect rule now distinguishes its two safe mechanisms. An
effect with a provider-native client key — an Issue upsert, a pull-request
upsert — reconciles on that key and carries no attempt state; creating an
object is not by itself what makes an effect attempt-stateful. A comment has
neither a native key nor a pre-existing subject, which is why it needs the
marker and the unattempted/attempted distinction. An effect with neither
mechanism refuses before its first mutation, as an intentional constraint.
3. Completed replay may reach and read the run's durable owner — lifecycle
storage access, not external-effect replay — while attaching no external-effect
provider, performing no effect again and starting no native operation. The
"no remote storage session" wording is gone from every document.
4. The authored comment body is preserved byte for byte as the authored portion
of the projection, with transport metadata outside it, rather than the provider
payload being claimed to equal the authored bytes.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SP9dEis51dcwBnwdaXZQAg
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@minkimcello
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

🏭 Complete the software-factory contract above PR #630 - #736

Open
minkimcello wants to merge 5 commits into
taras:codex/github-actions-software-factory-architecturefrom
minkimcello:claude/710-software-factory-contract
Open

🏭 Complete the software-factory contract above PR #630#736
minkimcello wants to merge 5 commits into
taras:codex/github-actions-software-factory-architecturefrom
minkimcello:claude/710-software-factory-contract

Conversation

@minkimcello

Copy link
Copy Markdown

Why

Closes#710.

The implementation stories under #633 need one decision-complete software-factory contract before they can build provider, ingress, Git, evidence, and factory behavior without choosing architecture independently. This PR completes that contract on top of the draft architecture in #630.

What changes

Before:

The draft architecture left deployment ownership, conflict behavior, durable identity, authority, target publication, replay, and terminal outcomes incomplete or distributed across documents.

After:

The architecture and specifications define the Cloudflare Durable Object owner, connection-scoped executor acquisition, GitHub intake and permission boundaries, stable run and effect identities, exact Git and target-publication behavior, machine waits, reconciliation, replay, abandonment, and the public construct inventory consumed by F1–F6.

How it works

GitHub intake and Actions execution → one durable run owner → provider-neutral effects and retained lifecycle → exact terminal reconciliation

Review guide

Start with:specs/github-actions-software-factory-spec.md

Then review:

  1. architecture.md for topology, principals, ownership, and durable boundaries.
  2. specs/workflow-spec.md for provider-neutral lifecycle and host contracts.
  3. specs/workflow-workspace-spec.md for effect, wait, reconciliation, and replay semantics.
  4. specs/executable-mdx-spec.md for the frozen conformance inventory.

Look carefully at:

  • The separation between typed-answer suspensions and provider-state machine waits.
  • Connection-scoped executor authority and transaction ownership.
  • Idempotency, attempt-state ambiguity, and completed replay without external-provider attachment.

What must stay true

  • One Durable Object owns one run's durable state; ephemeral runners own Git, evidence processes, and Agent clients.
  • Every protected mutation validates the live acquisition and expected Workspace root in its transaction.
  • External effects reconcile through their specified natural keys and fail closed on ambiguous attempted creation.
  • Completed replay reads only the durable owner and performs no external effect again.

How to verify it

Scope

Included

Intentionally unchanged

Risks and limitations

  • This PR is stacked on PR 🏭 Specify the GitHub Actions-hosted AI software factory #630. Descendant implementation branches must use accepted commit 817d3dd36cb07fddd972c6ae33716444f3cb75da as their exact contract base and be reconciled if that contract changes.
  • Recovery: amend this contract explicitly and restack affected descendants; do not repair structural omissions privately in an implementation PR.

Scope confirmation

  • Every changed file supports the purpose described above.
  • Unrelated cleanup and formatting changes are excluded.
  • Generated or mechanical changes are clearly identified.
  • The description matches the final diff and test results.

minkimcelloand others added 5 commits September 2, 2026 09:33
Turn PR taras#630's draft into a decision-complete first-release architecture. No
product, deployment, authority, identity, ownership, failure, replay, public
form, permission or ordering decision is left for a later Implementor.
The factory specification now settles: the canonical `github-issue-v1` run-ID
derivation and unsupported issue-transfer drift; `User` as the only Stage 1
spelling; the deployment topology of one SQLite-backed Cloudflare Durable
Object, an authenticated executor WebSocket, an ephemeral Actions runner and a
dedicated GitHub App; authenticated ingress order, bounded intake, dispatch
payload and OIDC claims; the exact App permissions, host ceilings, human
permission floor and `.github/workflows/**` denial; suspend-on-every-conflict
as the single Stage 4 profile; the Stage 7 trusted merge, `Git.PublishTarget`
compare-and-swap and remote-effect-before-terminal ordering; and the exact
public contract inventory. Section 8's remaining material decisions are gone.
architecture.md gains the terminology, the remote storage and executor
topology, the delivery-plane generalization, the Project-provider boundary,
comments/readiness/closure, ordered merge, target publication, trusted evidence
execution, terminal settlement, the split trusted host, and ten construct
inventory rows marked "specified by taras#710; implementation unbuilt".
The workflow and Workspace specifications gain the remote host, the executor
connection, which requests need it and which do not, the host-derived public
run ID, and provider-neutral contracts for `Git.Merge`, `Git.PublishTarget`,
`PullRequest.Comment`/`Ready`/`Close`, `Issue.Comment`/`Close`, `Evidence.Run`
and `Project.Status` — none of them reachable by an Agent or generated XMD,
whose write table stays exactly `File:write`, `Dir` and `File.Delete`. The
executable-MDX specification gains the exact authored forms and the frozen
WRH/WGI/WGE/WGM/WER/WFP/WFL acceptance tiers.
Documentation only: no production code, workflow YAML, dependency, generated
artifact or executable fixture changes, and the ownership SVG already agrees
with the amended text.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SP9dEis51dcwBnwdaXZQAg
Answer the Architect's three blocking findings on 86a4694. The public contracts
are now closed shapes rather than descriptions of shapes, run identity has one
spelling, and the two terminal paths are separate everywhere.
Finding 1 — exact bindings and durable records. specs/workflow-workspace-spec.md
is the normative schema location for every authored construct: §7.8 defines the
`GitMergeResult` clean/conflicted union, the conflict-entry record, its sorting,
duplicate and missing-side rules, and restoration failure; §7.9 defines the
`Git.PublishTarget` request and result with five exhaustive pre-states; §7.10
defines the comment request/result and how an engine-derived effect identity is
made remotely observable without using body text, plus literal `Ready`/`Close`
bindings; §10.3 does the same for `Issue.Comment` and `Issue.Close`; §10.5
settles `Evidence.Run` — the whole list runs, separate bounded stdout and stderr
with stated truncation, and an explicit table of which cases bind, which fail
and which commit nothing, with cancellation and teardown precedence fixed; §10.6
defines `Project.Status`. The factory specification §11.2 defines the versioned
closed factory protocol schemas — subject, stage, revision, handoff, actor,
outcome, invalidation, verdicts, conflict suspension, Stage 7 decisions, the
frontier and its complete reduction table, and the two asymmetric terminals.
Finding 1 also adds `PullRequest.Merged` (§7.11), the reconciled Git-host
observation that owns the post-publication merged fact, and settles the remote
host boundary (§13.2): the existing four-method `WorkflowHost` stays the host
assembly contract with a Cloudflare implementation beside the Deno one, the
runner-to-owner transport is a closed versioned envelope that refuses rather
than adapts, and an ownership table says which side owns each concern.
Finding 2 — every restatement of the run-ID derivation now uses `canonical
GitHub authority` byte for byte; the undefined Issue-provider spelling is gone.
Finding 3 — architecture.md and the factory specification now state the merged
and abandoned paths as separate ordered step lists, and the terminal record's
two shapes differ exactly as the paths do, so neither can be read as requiring
the other's effects.
Inventories, evidence tiers and the acceptance checklist are reconciled with all
of it. Documentation only; the ownership SVG is untouched.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SP9dEis51dcwBnwdaXZQAg
Apply rulings A-K from the Architect's answers on 80884f9.
A. Keep the four-method `WorkflowHost` and add that its transition and request
types — `WorkflowExecutionTransitions`, `WorkflowBeginRequest`,
`WorkflowExecutionBegun`, `WorkflowForkRequest`, `WorkflowForkSelection`,
`WorkflowRunCreation` — are provider-neutral and become package-root public
types, with runtime-named entrypoints keeping implementations and retained
encodings. Recorded as authorized future export work, not performed here.
B. `Evidence.Run` becomes an ordered fail-fast pipeline binding the executed
prefix: `{ completion, authoredCommands, executed, runTimeout? }`, rows carrying
`limit` for whichever of the two host-owned ceilings fired, a `runTimeout`
record for a whole-run expiry between commands rather than a fabricated argv
row, timeouts as ordinary unsuccessful outcomes, and fixed precedence —
cancellation over everything, first infrastructure failure authoritative with a
later teardown failure as secondary evidence, teardown authoritative alone —
with bounded diagnostic evidence retained on a failed effect's Error.
C. A comment provider must support a stable opaque correlation marker or refuse
before its first mutation. The authored logical body is preserved byte for byte
and the correlation representation rides outside it. Absence is now judged
against attempt state: no marker after an attempted-but-uncommitted creation is
permanent ambiguity, not proven absence.
D. `PullRequest.Merged` splits still-open (temporary unavailability) from
closed-unmerged (conflict), and the factory gains §10.4 — a bounded
host-configured retry, then a durable machine wait with its own protocol record,
woken by intake or an explicit resume and carrying no verdict.
E. A configured total bijection between the nine stages and nine exact Project
status option IDs, validated against a complete reread and refusing before any
intake, token, run or projection.
F. `Git.Merge`'s `purpose` is validated authorization against the
provider-authenticated merge ceiling, not write-only provenance.
G. The `RunnerRequest` envelope is deleted. The runner and owner ship as one
release identity checked by build fingerprint at admission; the messages are
private, while the owner-side authority invariants stay public and exact.
H. `FactoryTerminal` keeps journal event references, with cross-path, kind,
completeness and agreement validation spelled out.
I. The factory protocol schemas stay in the factory specification §11.2; the
other four documents link rather than duplicate.
J/K. Mixed wrapping left alone, new prose unwrapped; the tenth construct is
reflected everywhere.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SP9dEis51dcwBnwdaXZQAg
taras#710)
Ruling C asked for the comment contracts, the architecture, the WGE evidence and
the generic external-effect explanation to agree. The first three landed in
0d08dcc; §10.2 did not.
Split the two kinds of reconciled effect where the difference actually lives.
An effect that mutates a subject already there — Push, a numbered pull-request
update, ready, close, issue close, Project status — reads that subject, and a
complete observation is decisive whether or not the effect has attempted
anything. An effect that creates a new object the host names has nothing
pre-existing to read and no client-supplied idempotency key, so its completion
is visible only through a correlation value it wrote itself, and absence means a
different thing before and after a mutation has been attempted.
Only the second kind carries attempt state, and it narrows the decision in one
place: unattempted with nothing found performs once, while attempted with no
committed completion and nothing found is permanent ambiguity rather than
absence. A provider that cannot write, preserve and completely query such a
value refuses the effect from observation.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SP9dEis51dcwBnwdaXZQAg
Four narrow corrections from the Architect's verdict on b364b98.
1. The merged-observation wait is not a typed-answer suspension. A machine wait
is a second durable wait kind inside the existing lifecycle: it asks nobody
anything and ends because a later execution observed a provider again, so it
has no response schema, no `xmd workflow answer` route, no form and no bound
value, and it publishes no `suspension_request` and consumes no
`suspension_answer`. It shares only the atomic boundary — its `machine_wait`
event and the `suspended` status commit together, and the acquisition is
released after that commit. Its identity is a `waitId`, never a suspension ID;
`MergedObservationWait.suspensionId` becomes `waitId`, while
`ConflictSuspension.suspensionId` and the typed-answer protocol are untouched.
A new `MergedObservationWake` names the same `waitId` and a closed `source`,
with `intakeId` required exactly for a provider intake and absent exactly for
an operator resume. Waking is permission to look again: the intake retains a
bounded notification carrying no answer, verdict, stage, transition or
observation result, a later executor consumes it and appends the wake event in
one transaction, and a resume without a pending wake or operator authority
reports the same wait and settles suspended again.
2. The generic create-effect rule now distinguishes its two safe mechanisms. An
effect with a provider-native client key — an Issue upsert, a pull-request
upsert — reconciles on that key and carries no attempt state; creating an
object is not by itself what makes an effect attempt-stateful. A comment has
neither a native key nor a pre-existing subject, which is why it needs the
marker and the unattempted/attempted distinction. An effect with neither
mechanism refuses before its first mutation, as an intentional constraint.
3. Completed replay may reach and read the run's durable owner — lifecycle
storage access, not external-effect replay — while attaching no external-effect
provider, performing no effect again and starting no native operation. The
"no remote storage session" wording is gone from every document.
4. The authored comment body is preserved byte for byte as the authored portion
of the projection, with transport metadata outside it, rather than the provider
payload being claimed to equal the authored bytes.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SP9dEis51dcwBnwdaXZQAg
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@minkimcello
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

🏭 Complete the software-factory contract above PR #630 - #736

Open
minkimcello wants to merge 5 commits into
taras:codex/github-actions-software-factory-architecturefrom
minkimcello:claude/710-software-factory-contract
Open

🏭 Complete the software-factory contract above PR #630#736
minkimcello wants to merge 5 commits into
taras:codex/github-actions-software-factory-architecturefrom
minkimcello:claude/710-software-factory-contract

Conversation

@minkimcello

Copy link
Copy Markdown

Why

Closes#710.

The implementation stories under #633 need one decision-complete software-factory contract before they can build provider, ingress, Git, evidence, and factory behavior without choosing architecture independently. This PR completes that contract on top of the draft architecture in #630.

What changes

Before:

The draft architecture left deployment ownership, conflict behavior, durable identity, authority, target publication, replay, and terminal outcomes incomplete or distributed across documents.

After:

The architecture and specifications define the Cloudflare Durable Object owner, connection-scoped executor acquisition, GitHub intake and permission boundaries, stable run and effect identities, exact Git and target-publication behavior, machine waits, reconciliation, replay, abandonment, and the public construct inventory consumed by F1–F6.

How it works

GitHub intake and Actions execution → one durable run owner → provider-neutral effects and retained lifecycle → exact terminal reconciliation

Review guide

Start with:specs/github-actions-software-factory-spec.md

Then review:

  1. architecture.md for topology, principals, ownership, and durable boundaries.
  2. specs/workflow-spec.md for provider-neutral lifecycle and host contracts.
  3. specs/workflow-workspace-spec.md for effect, wait, reconciliation, and replay semantics.
  4. specs/executable-mdx-spec.md for the frozen conformance inventory.

Look carefully at:

  • The separation between typed-answer suspensions and provider-state machine waits.
  • Connection-scoped executor authority and transaction ownership.
  • Idempotency, attempt-state ambiguity, and completed replay without external-provider attachment.

What must stay true

  • One Durable Object owns one run's durable state; ephemeral runners own Git, evidence processes, and Agent clients.
  • Every protected mutation validates the live acquisition and expected Workspace root in its transaction.
  • External effects reconcile through their specified natural keys and fail closed on ambiguous attempted creation.
  • Completed replay reads only the durable owner and performs no external effect again.

How to verify it

Scope

Included

Intentionally unchanged

Risks and limitations

  • This PR is stacked on PR 🏭 Specify the GitHub Actions-hosted AI software factory #630. Descendant implementation branches must use accepted commit 817d3dd36cb07fddd972c6ae33716444f3cb75da as their exact contract base and be reconciled if that contract changes.
  • Recovery: amend this contract explicitly and restack affected descendants; do not repair structural omissions privately in an implementation PR.

Scope confirmation

  • Every changed file supports the purpose described above.
  • Unrelated cleanup and formatting changes are excluded.
  • Generated or mechanical changes are clearly identified.
  • The description matches the final diff and test results.

minkimcelloand others added 5 commits September 2, 2026 09:33
Turn PR taras#630's draft into a decision-complete first-release architecture. No
product, deployment, authority, identity, ownership, failure, replay, public
form, permission or ordering decision is left for a later Implementor.
The factory specification now settles: the canonical `github-issue-v1` run-ID
derivation and unsupported issue-transfer drift; `User` as the only Stage 1
spelling; the deployment topology of one SQLite-backed Cloudflare Durable
Object, an authenticated executor WebSocket, an ephemeral Actions runner and a
dedicated GitHub App; authenticated ingress order, bounded intake, dispatch
payload and OIDC claims; the exact App permissions, host ceilings, human
permission floor and `.github/workflows/**` denial; suspend-on-every-conflict
as the single Stage 4 profile; the Stage 7 trusted merge, `Git.PublishTarget`
compare-and-swap and remote-effect-before-terminal ordering; and the exact
public contract inventory. Section 8's remaining material decisions are gone.
architecture.md gains the terminology, the remote storage and executor
topology, the delivery-plane generalization, the Project-provider boundary,
comments/readiness/closure, ordered merge, target publication, trusted evidence
execution, terminal settlement, the split trusted host, and ten construct
inventory rows marked "specified by taras#710; implementation unbuilt".
The workflow and Workspace specifications gain the remote host, the executor
connection, which requests need it and which do not, the host-derived public
run ID, and provider-neutral contracts for `Git.Merge`, `Git.PublishTarget`,
`PullRequest.Comment`/`Ready`/`Close`, `Issue.Comment`/`Close`, `Evidence.Run`
and `Project.Status` — none of them reachable by an Agent or generated XMD,
whose write table stays exactly `File:write`, `Dir` and `File.Delete`. The
executable-MDX specification gains the exact authored forms and the frozen
WRH/WGI/WGE/WGM/WER/WFP/WFL acceptance tiers.
Documentation only: no production code, workflow YAML, dependency, generated
artifact or executable fixture changes, and the ownership SVG already agrees
with the amended text.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SP9dEis51dcwBnwdaXZQAg
Answer the Architect's three blocking findings on 86a4694. The public contracts
are now closed shapes rather than descriptions of shapes, run identity has one
spelling, and the two terminal paths are separate everywhere.
Finding 1 — exact bindings and durable records. specs/workflow-workspace-spec.md
is the normative schema location for every authored construct: §7.8 defines the
`GitMergeResult` clean/conflicted union, the conflict-entry record, its sorting,
duplicate and missing-side rules, and restoration failure; §7.9 defines the
`Git.PublishTarget` request and result with five exhaustive pre-states; §7.10
defines the comment request/result and how an engine-derived effect identity is
made remotely observable without using body text, plus literal `Ready`/`Close`
bindings; §10.3 does the same for `Issue.Comment` and `Issue.Close`; §10.5
settles `Evidence.Run` — the whole list runs, separate bounded stdout and stderr
with stated truncation, and an explicit table of which cases bind, which fail
and which commit nothing, with cancellation and teardown precedence fixed; §10.6
defines `Project.Status`. The factory specification §11.2 defines the versioned
closed factory protocol schemas — subject, stage, revision, handoff, actor,
outcome, invalidation, verdicts, conflict suspension, Stage 7 decisions, the
frontier and its complete reduction table, and the two asymmetric terminals.
Finding 1 also adds `PullRequest.Merged` (§7.11), the reconciled Git-host
observation that owns the post-publication merged fact, and settles the remote
host boundary (§13.2): the existing four-method `WorkflowHost` stays the host
assembly contract with a Cloudflare implementation beside the Deno one, the
runner-to-owner transport is a closed versioned envelope that refuses rather
than adapts, and an ownership table says which side owns each concern.
Finding 2 — every restatement of the run-ID derivation now uses `canonical
GitHub authority` byte for byte; the undefined Issue-provider spelling is gone.
Finding 3 — architecture.md and the factory specification now state the merged
and abandoned paths as separate ordered step lists, and the terminal record's
two shapes differ exactly as the paths do, so neither can be read as requiring
the other's effects.
Inventories, evidence tiers and the acceptance checklist are reconciled with all
of it. Documentation only; the ownership SVG is untouched.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SP9dEis51dcwBnwdaXZQAg
Apply rulings A-K from the Architect's answers on 80884f9.
A. Keep the four-method `WorkflowHost` and add that its transition and request
types — `WorkflowExecutionTransitions`, `WorkflowBeginRequest`,
`WorkflowExecutionBegun`, `WorkflowForkRequest`, `WorkflowForkSelection`,
`WorkflowRunCreation` — are provider-neutral and become package-root public
types, with runtime-named entrypoints keeping implementations and retained
encodings. Recorded as authorized future export work, not performed here.
B. `Evidence.Run` becomes an ordered fail-fast pipeline binding the executed
prefix: `{ completion, authoredCommands, executed, runTimeout? }`, rows carrying
`limit` for whichever of the two host-owned ceilings fired, a `runTimeout`
record for a whole-run expiry between commands rather than a fabricated argv
row, timeouts as ordinary unsuccessful outcomes, and fixed precedence —
cancellation over everything, first infrastructure failure authoritative with a
later teardown failure as secondary evidence, teardown authoritative alone —
with bounded diagnostic evidence retained on a failed effect's Error.
C. A comment provider must support a stable opaque correlation marker or refuse
before its first mutation. The authored logical body is preserved byte for byte
and the correlation representation rides outside it. Absence is now judged
against attempt state: no marker after an attempted-but-uncommitted creation is
permanent ambiguity, not proven absence.
D. `PullRequest.Merged` splits still-open (temporary unavailability) from
closed-unmerged (conflict), and the factory gains §10.4 — a bounded
host-configured retry, then a durable machine wait with its own protocol record,
woken by intake or an explicit resume and carrying no verdict.
E. A configured total bijection between the nine stages and nine exact Project
status option IDs, validated against a complete reread and refusing before any
intake, token, run or projection.
F. `Git.Merge`'s `purpose` is validated authorization against the
provider-authenticated merge ceiling, not write-only provenance.
G. The `RunnerRequest` envelope is deleted. The runner and owner ship as one
release identity checked by build fingerprint at admission; the messages are
private, while the owner-side authority invariants stay public and exact.
H. `FactoryTerminal` keeps journal event references, with cross-path, kind,
completeness and agreement validation spelled out.
I. The factory protocol schemas stay in the factory specification §11.2; the
other four documents link rather than duplicate.
J/K. Mixed wrapping left alone, new prose unwrapped; the tenth construct is
reflected everywhere.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SP9dEis51dcwBnwdaXZQAg
taras#710)
Ruling C asked for the comment contracts, the architecture, the WGE evidence and
the generic external-effect explanation to agree. The first three landed in
0d08dcc; §10.2 did not.
Split the two kinds of reconciled effect where the difference actually lives.
An effect that mutates a subject already there — Push, a numbered pull-request
update, ready, close, issue close, Project status — reads that subject, and a
complete observation is decisive whether or not the effect has attempted
anything. An effect that creates a new object the host names has nothing
pre-existing to read and no client-supplied idempotency key, so its completion
is visible only through a correlation value it wrote itself, and absence means a
different thing before and after a mutation has been attempted.
Only the second kind carries attempt state, and it narrows the decision in one
place: unattempted with nothing found performs once, while attempted with no
committed completion and nothing found is permanent ambiguity rather than
absence. A provider that cannot write, preserve and completely query such a
value refuses the effect from observation.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SP9dEis51dcwBnwdaXZQAg
Four narrow corrections from the Architect's verdict on b364b98.
1. The merged-observation wait is not a typed-answer suspension. A machine wait
is a second durable wait kind inside the existing lifecycle: it asks nobody
anything and ends because a later execution observed a provider again, so it
has no response schema, no `xmd workflow answer` route, no form and no bound
value, and it publishes no `suspension_request` and consumes no
`suspension_answer`. It shares only the atomic boundary — its `machine_wait`
event and the `suspended` status commit together, and the acquisition is
released after that commit. Its identity is a `waitId`, never a suspension ID;
`MergedObservationWait.suspensionId` becomes `waitId`, while
`ConflictSuspension.suspensionId` and the typed-answer protocol are untouched.
A new `MergedObservationWake` names the same `waitId` and a closed `source`,
with `intakeId` required exactly for a provider intake and absent exactly for
an operator resume. Waking is permission to look again: the intake retains a
bounded notification carrying no answer, verdict, stage, transition or
observation result, a later executor consumes it and appends the wake event in
one transaction, and a resume without a pending wake or operator authority
reports the same wait and settles suspended again.
2. The generic create-effect rule now distinguishes its two safe mechanisms. An
effect with a provider-native client key — an Issue upsert, a pull-request
upsert — reconciles on that key and carries no attempt state; creating an
object is not by itself what makes an effect attempt-stateful. A comment has
neither a native key nor a pre-existing subject, which is why it needs the
marker and the unattempted/attempted distinction. An effect with neither
mechanism refuses before its first mutation, as an intentional constraint.
3. Completed replay may reach and read the run's durable owner — lifecycle
storage access, not external-effect replay — while attaching no external-effect
provider, performing no effect again and starting no native operation. The
"no remote storage session" wording is gone from every document.
4. The authored comment body is preserved byte for byte as the authored portion
of the projection, with transport metadata outside it, rather than the provider
payload being claimed to equal the authored bytes.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SP9dEis51dcwBnwdaXZQAg
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@minkimcello
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

🏭 Complete the software-factory contract above PR #630 - #736

Open
minkimcello wants to merge 5 commits into
taras:codex/github-actions-software-factory-architecturefrom
minkimcello:claude/710-software-factory-contract
Open

🏭 Complete the software-factory contract above PR #630#736
minkimcello wants to merge 5 commits into
taras:codex/github-actions-software-factory-architecturefrom
minkimcello:claude/710-software-factory-contract

Conversation

@minkimcello

Copy link
Copy Markdown

Why

Closes#710.

The implementation stories under #633 need one decision-complete software-factory contract before they can build provider, ingress, Git, evidence, and factory behavior without choosing architecture independently. This PR completes that contract on top of the draft architecture in #630.

What changes

Before:

The draft architecture left deployment ownership, conflict behavior, durable identity, authority, target publication, replay, and terminal outcomes incomplete or distributed across documents.

After:

The architecture and specifications define the Cloudflare Durable Object owner, connection-scoped executor acquisition, GitHub intake and permission boundaries, stable run and effect identities, exact Git and target-publication behavior, machine waits, reconciliation, replay, abandonment, and the public construct inventory consumed by F1–F6.

How it works

GitHub intake and Actions execution → one durable run owner → provider-neutral effects and retained lifecycle → exact terminal reconciliation

Review guide

Start with:specs/github-actions-software-factory-spec.md

Then review:

  1. architecture.md for topology, principals, ownership, and durable boundaries.
  2. specs/workflow-spec.md for provider-neutral lifecycle and host contracts.
  3. specs/workflow-workspace-spec.md for effect, wait, reconciliation, and replay semantics.
  4. specs/executable-mdx-spec.md for the frozen conformance inventory.

Look carefully at:

  • The separation between typed-answer suspensions and provider-state machine waits.
  • Connection-scoped executor authority and transaction ownership.
  • Idempotency, attempt-state ambiguity, and completed replay without external-provider attachment.

What must stay true

  • One Durable Object owns one run's durable state; ephemeral runners own Git, evidence processes, and Agent clients.
  • Every protected mutation validates the live acquisition and expected Workspace root in its transaction.
  • External effects reconcile through their specified natural keys and fail closed on ambiguous attempted creation.
  • Completed replay reads only the durable owner and performs no external effect again.

How to verify it

Scope

Included

Intentionally unchanged

Risks and limitations

  • This PR is stacked on PR 🏭 Specify the GitHub Actions-hosted AI software factory #630. Descendant implementation branches must use accepted commit 817d3dd36cb07fddd972c6ae33716444f3cb75da as their exact contract base and be reconciled if that contract changes.
  • Recovery: amend this contract explicitly and restack affected descendants; do not repair structural omissions privately in an implementation PR.

Scope confirmation

  • Every changed file supports the purpose described above.
  • Unrelated cleanup and formatting changes are excluded.
  • Generated or mechanical changes are clearly identified.
  • The description matches the final diff and test results.

minkimcelloand others added 5 commits September 2, 2026 09:33
Turn PR taras#630's draft into a decision-complete first-release architecture. No
product, deployment, authority, identity, ownership, failure, replay, public
form, permission or ordering decision is left for a later Implementor.
The factory specification now settles: the canonical `github-issue-v1` run-ID
derivation and unsupported issue-transfer drift; `User` as the only Stage 1
spelling; the deployment topology of one SQLite-backed Cloudflare Durable
Object, an authenticated executor WebSocket, an ephemeral Actions runner and a
dedicated GitHub App; authenticated ingress order, bounded intake, dispatch
payload and OIDC claims; the exact App permissions, host ceilings, human
permission floor and `.github/workflows/**` denial; suspend-on-every-conflict
as the single Stage 4 profile; the Stage 7 trusted merge, `Git.PublishTarget`
compare-and-swap and remote-effect-before-terminal ordering; and the exact
public contract inventory. Section 8's remaining material decisions are gone.
architecture.md gains the terminology, the remote storage and executor
topology, the delivery-plane generalization, the Project-provider boundary,
comments/readiness/closure, ordered merge, target publication, trusted evidence
execution, terminal settlement, the split trusted host, and ten construct
inventory rows marked "specified by taras#710; implementation unbuilt".
The workflow and Workspace specifications gain the remote host, the executor
connection, which requests need it and which do not, the host-derived public
run ID, and provider-neutral contracts for `Git.Merge`, `Git.PublishTarget`,
`PullRequest.Comment`/`Ready`/`Close`, `Issue.Comment`/`Close`, `Evidence.Run`
and `Project.Status` — none of them reachable by an Agent or generated XMD,
whose write table stays exactly `File:write`, `Dir` and `File.Delete`. The
executable-MDX specification gains the exact authored forms and the frozen
WRH/WGI/WGE/WGM/WER/WFP/WFL acceptance tiers.
Documentation only: no production code, workflow YAML, dependency, generated
artifact or executable fixture changes, and the ownership SVG already agrees
with the amended text.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SP9dEis51dcwBnwdaXZQAg
Answer the Architect's three blocking findings on 86a4694. The public contracts
are now closed shapes rather than descriptions of shapes, run identity has one
spelling, and the two terminal paths are separate everywhere.
Finding 1 — exact bindings and durable records. specs/workflow-workspace-spec.md
is the normative schema location for every authored construct: §7.8 defines the
`GitMergeResult` clean/conflicted union, the conflict-entry record, its sorting,
duplicate and missing-side rules, and restoration failure; §7.9 defines the
`Git.PublishTarget` request and result with five exhaustive pre-states; §7.10
defines the comment request/result and how an engine-derived effect identity is
made remotely observable without using body text, plus literal `Ready`/`Close`
bindings; §10.3 does the same for `Issue.Comment` and `Issue.Close`; §10.5
settles `Evidence.Run` — the whole list runs, separate bounded stdout and stderr
with stated truncation, and an explicit table of which cases bind, which fail
and which commit nothing, with cancellation and teardown precedence fixed; §10.6
defines `Project.Status`. The factory specification §11.2 defines the versioned
closed factory protocol schemas — subject, stage, revision, handoff, actor,
outcome, invalidation, verdicts, conflict suspension, Stage 7 decisions, the
frontier and its complete reduction table, and the two asymmetric terminals.
Finding 1 also adds `PullRequest.Merged` (§7.11), the reconciled Git-host
observation that owns the post-publication merged fact, and settles the remote
host boundary (§13.2): the existing four-method `WorkflowHost` stays the host
assembly contract with a Cloudflare implementation beside the Deno one, the
runner-to-owner transport is a closed versioned envelope that refuses rather
than adapts, and an ownership table says which side owns each concern.
Finding 2 — every restatement of the run-ID derivation now uses `canonical
GitHub authority` byte for byte; the undefined Issue-provider spelling is gone.
Finding 3 — architecture.md and the factory specification now state the merged
and abandoned paths as separate ordered step lists, and the terminal record's
two shapes differ exactly as the paths do, so neither can be read as requiring
the other's effects.
Inventories, evidence tiers and the acceptance checklist are reconciled with all
of it. Documentation only; the ownership SVG is untouched.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SP9dEis51dcwBnwdaXZQAg
Apply rulings A-K from the Architect's answers on 80884f9.
A. Keep the four-method `WorkflowHost` and add that its transition and request
types — `WorkflowExecutionTransitions`, `WorkflowBeginRequest`,
`WorkflowExecutionBegun`, `WorkflowForkRequest`, `WorkflowForkSelection`,
`WorkflowRunCreation` — are provider-neutral and become package-root public
types, with runtime-named entrypoints keeping implementations and retained
encodings. Recorded as authorized future export work, not performed here.
B. `Evidence.Run` becomes an ordered fail-fast pipeline binding the executed
prefix: `{ completion, authoredCommands, executed, runTimeout? }`, rows carrying
`limit` for whichever of the two host-owned ceilings fired, a `runTimeout`
record for a whole-run expiry between commands rather than a fabricated argv
row, timeouts as ordinary unsuccessful outcomes, and fixed precedence —
cancellation over everything, first infrastructure failure authoritative with a
later teardown failure as secondary evidence, teardown authoritative alone —
with bounded diagnostic evidence retained on a failed effect's Error.
C. A comment provider must support a stable opaque correlation marker or refuse
before its first mutation. The authored logical body is preserved byte for byte
and the correlation representation rides outside it. Absence is now judged
against attempt state: no marker after an attempted-but-uncommitted creation is
permanent ambiguity, not proven absence.
D. `PullRequest.Merged` splits still-open (temporary unavailability) from
closed-unmerged (conflict), and the factory gains §10.4 — a bounded
host-configured retry, then a durable machine wait with its own protocol record,
woken by intake or an explicit resume and carrying no verdict.
E. A configured total bijection between the nine stages and nine exact Project
status option IDs, validated against a complete reread and refusing before any
intake, token, run or projection.
F. `Git.Merge`'s `purpose` is validated authorization against the
provider-authenticated merge ceiling, not write-only provenance.
G. The `RunnerRequest` envelope is deleted. The runner and owner ship as one
release identity checked by build fingerprint at admission; the messages are
private, while the owner-side authority invariants stay public and exact.
H. `FactoryTerminal` keeps journal event references, with cross-path, kind,
completeness and agreement validation spelled out.
I. The factory protocol schemas stay in the factory specification §11.2; the
other four documents link rather than duplicate.
J/K. Mixed wrapping left alone, new prose unwrapped; the tenth construct is
reflected everywhere.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SP9dEis51dcwBnwdaXZQAg
taras#710)
Ruling C asked for the comment contracts, the architecture, the WGE evidence and
the generic external-effect explanation to agree. The first three landed in
0d08dcc; §10.2 did not.
Split the two kinds of reconciled effect where the difference actually lives.
An effect that mutates a subject already there — Push, a numbered pull-request
update, ready, close, issue close, Project status — reads that subject, and a
complete observation is decisive whether or not the effect has attempted
anything. An effect that creates a new object the host names has nothing
pre-existing to read and no client-supplied idempotency key, so its completion
is visible only through a correlation value it wrote itself, and absence means a
different thing before and after a mutation has been attempted.
Only the second kind carries attempt state, and it narrows the decision in one
place: unattempted with nothing found performs once, while attempted with no
committed completion and nothing found is permanent ambiguity rather than
absence. A provider that cannot write, preserve and completely query such a
value refuses the effect from observation.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SP9dEis51dcwBnwdaXZQAg
Four narrow corrections from the Architect's verdict on b364b98.
1. The merged-observation wait is not a typed-answer suspension. A machine wait
is a second durable wait kind inside the existing lifecycle: it asks nobody
anything and ends because a later execution observed a provider again, so it
has no response schema, no `xmd workflow answer` route, no form and no bound
value, and it publishes no `suspension_request` and consumes no
`suspension_answer`. It shares only the atomic boundary — its `machine_wait`
event and the `suspended` status commit together, and the acquisition is
released after that commit. Its identity is a `waitId`, never a suspension ID;
`MergedObservationWait.suspensionId` becomes `waitId`, while
`ConflictSuspension.suspensionId` and the typed-answer protocol are untouched.
A new `MergedObservationWake` names the same `waitId` and a closed `source`,
with `intakeId` required exactly for a provider intake and absent exactly for
an operator resume. Waking is permission to look again: the intake retains a
bounded notification carrying no answer, verdict, stage, transition or
observation result, a later executor consumes it and appends the wake event in
one transaction, and a resume without a pending wake or operator authority
reports the same wait and settles suspended again.
2. The generic create-effect rule now distinguishes its two safe mechanisms. An
effect with a provider-native client key — an Issue upsert, a pull-request
upsert — reconciles on that key and carries no attempt state; creating an
object is not by itself what makes an effect attempt-stateful. A comment has
neither a native key nor a pre-existing subject, which is why it needs the
marker and the unattempted/attempted distinction. An effect with neither
mechanism refuses before its first mutation, as an intentional constraint.
3. Completed replay may reach and read the run's durable owner — lifecycle
storage access, not external-effect replay — while attaching no external-effect
provider, performing no effect again and starting no native operation. The
"no remote storage session" wording is gone from every document.
4. The authored comment body is preserved byte for byte as the authored portion
of the projection, with transport metadata outside it, rather than the provider
payload being claimed to equal the authored bytes.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SP9dEis51dcwBnwdaXZQAg
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@minkimcello
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

🏭 Complete the software-factory contract above PR #630 - #736

Open
minkimcello wants to merge 5 commits into
taras:codex/github-actions-software-factory-architecturefrom
minkimcello:claude/710-software-factory-contract
Open

🏭 Complete the software-factory contract above PR #630#736
minkimcello wants to merge 5 commits into
taras:codex/github-actions-software-factory-architecturefrom
minkimcello:claude/710-software-factory-contract

Conversation

@minkimcello

Copy link
Copy Markdown

Why

Closes#710.

The implementation stories under #633 need one decision-complete software-factory contract before they can build provider, ingress, Git, evidence, and factory behavior without choosing architecture independently. This PR completes that contract on top of the draft architecture in #630.

What changes

Before:

The draft architecture left deployment ownership, conflict behavior, durable identity, authority, target publication, replay, and terminal outcomes incomplete or distributed across documents.

After:

The architecture and specifications define the Cloudflare Durable Object owner, connection-scoped executor acquisition, GitHub intake and permission boundaries, stable run and effect identities, exact Git and target-publication behavior, machine waits, reconciliation, replay, abandonment, and the public construct inventory consumed by F1–F6.

How it works

GitHub intake and Actions execution → one durable run owner → provider-neutral effects and retained lifecycle → exact terminal reconciliation

Review guide

Start with:specs/github-actions-software-factory-spec.md

Then review:

  1. architecture.md for topology, principals, ownership, and durable boundaries.
  2. specs/workflow-spec.md for provider-neutral lifecycle and host contracts.
  3. specs/workflow-workspace-spec.md for effect, wait, reconciliation, and replay semantics.
  4. specs/executable-mdx-spec.md for the frozen conformance inventory.

Look carefully at:

  • The separation between typed-answer suspensions and provider-state machine waits.
  • Connection-scoped executor authority and transaction ownership.
  • Idempotency, attempt-state ambiguity, and completed replay without external-provider attachment.

What must stay true

  • One Durable Object owns one run's durable state; ephemeral runners own Git, evidence processes, and Agent clients.
  • Every protected mutation validates the live acquisition and expected Workspace root in its transaction.
  • External effects reconcile through their specified natural keys and fail closed on ambiguous attempted creation.
  • Completed replay reads only the durable owner and performs no external effect again.

How to verify it

Scope

Included

Intentionally unchanged

Risks and limitations

  • This PR is stacked on PR 🏭 Specify the GitHub Actions-hosted AI software factory #630. Descendant implementation branches must use accepted commit 817d3dd36cb07fddd972c6ae33716444f3cb75da as their exact contract base and be reconciled if that contract changes.
  • Recovery: amend this contract explicitly and restack affected descendants; do not repair structural omissions privately in an implementation PR.

Scope confirmation

  • Every changed file supports the purpose described above.
  • Unrelated cleanup and formatting changes are excluded.
  • Generated or mechanical changes are clearly identified.
  • The description matches the final diff and test results.

minkimcelloand others added 5 commits September 2, 2026 09:33
Turn PR taras#630's draft into a decision-complete first-release architecture. No
product, deployment, authority, identity, ownership, failure, replay, public
form, permission or ordering decision is left for a later Implementor.
The factory specification now settles: the canonical `github-issue-v1` run-ID
derivation and unsupported issue-transfer drift; `User` as the only Stage 1
spelling; the deployment topology of one SQLite-backed Cloudflare Durable
Object, an authenticated executor WebSocket, an ephemeral Actions runner and a
dedicated GitHub App; authenticated ingress order, bounded intake, dispatch
payload and OIDC claims; the exact App permissions, host ceilings, human
permission floor and `.github/workflows/**` denial; suspend-on-every-conflict
as the single Stage 4 profile; the Stage 7 trusted merge, `Git.PublishTarget`
compare-and-swap and remote-effect-before-terminal ordering; and the exact
public contract inventory. Section 8's remaining material decisions are gone.
architecture.md gains the terminology, the remote storage and executor
topology, the delivery-plane generalization, the Project-provider boundary,
comments/readiness/closure, ordered merge, target publication, trusted evidence
execution, terminal settlement, the split trusted host, and ten construct
inventory rows marked "specified by taras#710; implementation unbuilt".
The workflow and Workspace specifications gain the remote host, the executor
connection, which requests need it and which do not, the host-derived public
run ID, and provider-neutral contracts for `Git.Merge`, `Git.PublishTarget`,
`PullRequest.Comment`/`Ready`/`Close`, `Issue.Comment`/`Close`, `Evidence.Run`
and `Project.Status` — none of them reachable by an Agent or generated XMD,
whose write table stays exactly `File:write`, `Dir` and `File.Delete`. The
executable-MDX specification gains the exact authored forms and the frozen
WRH/WGI/WGE/WGM/WER/WFP/WFL acceptance tiers.
Documentation only: no production code, workflow YAML, dependency, generated
artifact or executable fixture changes, and the ownership SVG already agrees
with the amended text.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SP9dEis51dcwBnwdaXZQAg
Answer the Architect's three blocking findings on 86a4694. The public contracts
are now closed shapes rather than descriptions of shapes, run identity has one
spelling, and the two terminal paths are separate everywhere.
Finding 1 — exact bindings and durable records. specs/workflow-workspace-spec.md
is the normative schema location for every authored construct: §7.8 defines the
`GitMergeResult` clean/conflicted union, the conflict-entry record, its sorting,
duplicate and missing-side rules, and restoration failure; §7.9 defines the
`Git.PublishTarget` request and result with five exhaustive pre-states; §7.10
defines the comment request/result and how an engine-derived effect identity is
made remotely observable without using body text, plus literal `Ready`/`Close`
bindings; §10.3 does the same for `Issue.Comment` and `Issue.Close`; §10.5
settles `Evidence.Run` — the whole list runs, separate bounded stdout and stderr
with stated truncation, and an explicit table of which cases bind, which fail
and which commit nothing, with cancellation and teardown precedence fixed; §10.6
defines `Project.Status`. The factory specification §11.2 defines the versioned
closed factory protocol schemas — subject, stage, revision, handoff, actor,
outcome, invalidation, verdicts, conflict suspension, Stage 7 decisions, the
frontier and its complete reduction table, and the two asymmetric terminals.
Finding 1 also adds `PullRequest.Merged` (§7.11), the reconciled Git-host
observation that owns the post-publication merged fact, and settles the remote
host boundary (§13.2): the existing four-method `WorkflowHost` stays the host
assembly contract with a Cloudflare implementation beside the Deno one, the
runner-to-owner transport is a closed versioned envelope that refuses rather
than adapts, and an ownership table says which side owns each concern.
Finding 2 — every restatement of the run-ID derivation now uses `canonical
GitHub authority` byte for byte; the undefined Issue-provider spelling is gone.
Finding 3 — architecture.md and the factory specification now state the merged
and abandoned paths as separate ordered step lists, and the terminal record's
two shapes differ exactly as the paths do, so neither can be read as requiring
the other's effects.
Inventories, evidence tiers and the acceptance checklist are reconciled with all
of it. Documentation only; the ownership SVG is untouched.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SP9dEis51dcwBnwdaXZQAg
Apply rulings A-K from the Architect's answers on 80884f9.
A. Keep the four-method `WorkflowHost` and add that its transition and request
types — `WorkflowExecutionTransitions`, `WorkflowBeginRequest`,
`WorkflowExecutionBegun`, `WorkflowForkRequest`, `WorkflowForkSelection`,
`WorkflowRunCreation` — are provider-neutral and become package-root public
types, with runtime-named entrypoints keeping implementations and retained
encodings. Recorded as authorized future export work, not performed here.
B. `Evidence.Run` becomes an ordered fail-fast pipeline binding the executed
prefix: `{ completion, authoredCommands, executed, runTimeout? }`, rows carrying
`limit` for whichever of the two host-owned ceilings fired, a `runTimeout`
record for a whole-run expiry between commands rather than a fabricated argv
row, timeouts as ordinary unsuccessful outcomes, and fixed precedence —
cancellation over everything, first infrastructure failure authoritative with a
later teardown failure as secondary evidence, teardown authoritative alone —
with bounded diagnostic evidence retained on a failed effect's Error.
C. A comment provider must support a stable opaque correlation marker or refuse
before its first mutation. The authored logical body is preserved byte for byte
and the correlation representation rides outside it. Absence is now judged
against attempt state: no marker after an attempted-but-uncommitted creation is
permanent ambiguity, not proven absence.
D. `PullRequest.Merged` splits still-open (temporary unavailability) from
closed-unmerged (conflict), and the factory gains §10.4 — a bounded
host-configured retry, then a durable machine wait with its own protocol record,
woken by intake or an explicit resume and carrying no verdict.
E. A configured total bijection between the nine stages and nine exact Project
status option IDs, validated against a complete reread and refusing before any
intake, token, run or projection.
F. `Git.Merge`'s `purpose` is validated authorization against the
provider-authenticated merge ceiling, not write-only provenance.
G. The `RunnerRequest` envelope is deleted. The runner and owner ship as one
release identity checked by build fingerprint at admission; the messages are
private, while the owner-side authority invariants stay public and exact.
H. `FactoryTerminal` keeps journal event references, with cross-path, kind,
completeness and agreement validation spelled out.
I. The factory protocol schemas stay in the factory specification §11.2; the
other four documents link rather than duplicate.
J/K. Mixed wrapping left alone, new prose unwrapped; the tenth construct is
reflected everywhere.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SP9dEis51dcwBnwdaXZQAg
taras#710)
Ruling C asked for the comment contracts, the architecture, the WGE evidence and
the generic external-effect explanation to agree. The first three landed in
0d08dcc; §10.2 did not.
Split the two kinds of reconciled effect where the difference actually lives.
An effect that mutates a subject already there — Push, a numbered pull-request
update, ready, close, issue close, Project status — reads that subject, and a
complete observation is decisive whether or not the effect has attempted
anything. An effect that creates a new object the host names has nothing
pre-existing to read and no client-supplied idempotency key, so its completion
is visible only through a correlation value it wrote itself, and absence means a
different thing before and after a mutation has been attempted.
Only the second kind carries attempt state, and it narrows the decision in one
place: unattempted with nothing found performs once, while attempted with no
committed completion and nothing found is permanent ambiguity rather than
absence. A provider that cannot write, preserve and completely query such a
value refuses the effect from observation.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SP9dEis51dcwBnwdaXZQAg
Four narrow corrections from the Architect's verdict on b364b98.
1. The merged-observation wait is not a typed-answer suspension. A machine wait
is a second durable wait kind inside the existing lifecycle: it asks nobody
anything and ends because a later execution observed a provider again, so it
has no response schema, no `xmd workflow answer` route, no form and no bound
value, and it publishes no `suspension_request` and consumes no
`suspension_answer`. It shares only the atomic boundary — its `machine_wait`
event and the `suspended` status commit together, and the acquisition is
released after that commit. Its identity is a `waitId`, never a suspension ID;
`MergedObservationWait.suspensionId` becomes `waitId`, while
`ConflictSuspension.suspensionId` and the typed-answer protocol are untouched.
A new `MergedObservationWake` names the same `waitId` and a closed `source`,
with `intakeId` required exactly for a provider intake and absent exactly for
an operator resume. Waking is permission to look again: the intake retains a
bounded notification carrying no answer, verdict, stage, transition or
observation result, a later executor consumes it and appends the wake event in
one transaction, and a resume without a pending wake or operator authority
reports the same wait and settles suspended again.
2. The generic create-effect rule now distinguishes its two safe mechanisms. An
effect with a provider-native client key — an Issue upsert, a pull-request
upsert — reconciles on that key and carries no attempt state; creating an
object is not by itself what makes an effect attempt-stateful. A comment has
neither a native key nor a pre-existing subject, which is why it needs the
marker and the unattempted/attempted distinction. An effect with neither
mechanism refuses before its first mutation, as an intentional constraint.
3. Completed replay may reach and read the run's durable owner — lifecycle
storage access, not external-effect replay — while attaching no external-effect
provider, performing no effect again and starting no native operation. The
"no remote storage session" wording is gone from every document.
4. The authored comment body is preserved byte for byte as the authored portion
of the projection, with transport metadata outside it, rather than the provider
payload being claimed to equal the authored bytes.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SP9dEis51dcwBnwdaXZQAg
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@minkimcello
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

🏭 Complete the software-factory contract above PR #630 - #736

Open
minkimcello wants to merge 5 commits into
taras:codex/github-actions-software-factory-architecturefrom
minkimcello:claude/710-software-factory-contract
Open

🏭 Complete the software-factory contract above PR #630#736
minkimcello wants to merge 5 commits into
taras:codex/github-actions-software-factory-architecturefrom
minkimcello:claude/710-software-factory-contract

Conversation

@minkimcello

Copy link
Copy Markdown

Why

Closes#710.

The implementation stories under #633 need one decision-complete software-factory contract before they can build provider, ingress, Git, evidence, and factory behavior without choosing architecture independently. This PR completes that contract on top of the draft architecture in #630.

What changes

Before:

The draft architecture left deployment ownership, conflict behavior, durable identity, authority, target publication, replay, and terminal outcomes incomplete or distributed across documents.

After:

The architecture and specifications define the Cloudflare Durable Object owner, connection-scoped executor acquisition, GitHub intake and permission boundaries, stable run and effect identities, exact Git and target-publication behavior, machine waits, reconciliation, replay, abandonment, and the public construct inventory consumed by F1–F6.

How it works

GitHub intake and Actions execution → one durable run owner → provider-neutral effects and retained lifecycle → exact terminal reconciliation

Review guide

Start with:specs/github-actions-software-factory-spec.md

Then review:

  1. architecture.md for topology, principals, ownership, and durable boundaries.
  2. specs/workflow-spec.md for provider-neutral lifecycle and host contracts.
  3. specs/workflow-workspace-spec.md for effect, wait, reconciliation, and replay semantics.
  4. specs/executable-mdx-spec.md for the frozen conformance inventory.

Look carefully at:

  • The separation between typed-answer suspensions and provider-state machine waits.
  • Connection-scoped executor authority and transaction ownership.
  • Idempotency, attempt-state ambiguity, and completed replay without external-provider attachment.

What must stay true

  • One Durable Object owns one run's durable state; ephemeral runners own Git, evidence processes, and Agent clients.
  • Every protected mutation validates the live acquisition and expected Workspace root in its transaction.
  • External effects reconcile through their specified natural keys and fail closed on ambiguous attempted creation.
  • Completed replay reads only the durable owner and performs no external effect again.

How to verify it

Scope

Included

Intentionally unchanged

Risks and limitations

  • This PR is stacked on PR 🏭 Specify the GitHub Actions-hosted AI software factory #630. Descendant implementation branches must use accepted commit 817d3dd36cb07fddd972c6ae33716444f3cb75da as their exact contract base and be reconciled if that contract changes.
  • Recovery: amend this contract explicitly and restack affected descendants; do not repair structural omissions privately in an implementation PR.

Scope confirmation

  • Every changed file supports the purpose described above.
  • Unrelated cleanup and formatting changes are excluded.
  • Generated or mechanical changes are clearly identified.
  • The description matches the final diff and test results.

minkimcelloand others added 5 commits September 2, 2026 09:33
Turn PR taras#630's draft into a decision-complete first-release architecture. No
product, deployment, authority, identity, ownership, failure, replay, public
form, permission or ordering decision is left for a later Implementor.
The factory specification now settles: the canonical `github-issue-v1` run-ID
derivation and unsupported issue-transfer drift; `User` as the only Stage 1
spelling; the deployment topology of one SQLite-backed Cloudflare Durable
Object, an authenticated executor WebSocket, an ephemeral Actions runner and a
dedicated GitHub App; authenticated ingress order, bounded intake, dispatch
payload and OIDC claims; the exact App permissions, host ceilings, human
permission floor and `.github/workflows/**` denial; suspend-on-every-conflict
as the single Stage 4 profile; the Stage 7 trusted merge, `Git.PublishTarget`
compare-and-swap and remote-effect-before-terminal ordering; and the exact
public contract inventory. Section 8's remaining material decisions are gone.
architecture.md gains the terminology, the remote storage and executor
topology, the delivery-plane generalization, the Project-provider boundary,
comments/readiness/closure, ordered merge, target publication, trusted evidence
execution, terminal settlement, the split trusted host, and ten construct
inventory rows marked "specified by taras#710; implementation unbuilt".
The workflow and Workspace specifications gain the remote host, the executor
connection, which requests need it and which do not, the host-derived public
run ID, and provider-neutral contracts for `Git.Merge`, `Git.PublishTarget`,
`PullRequest.Comment`/`Ready`/`Close`, `Issue.Comment`/`Close`, `Evidence.Run`
and `Project.Status` — none of them reachable by an Agent or generated XMD,
whose write table stays exactly `File:write`, `Dir` and `File.Delete`. The
executable-MDX specification gains the exact authored forms and the frozen
WRH/WGI/WGE/WGM/WER/WFP/WFL acceptance tiers.
Documentation only: no production code, workflow YAML, dependency, generated
artifact or executable fixture changes, and the ownership SVG already agrees
with the amended text.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SP9dEis51dcwBnwdaXZQAg
Answer the Architect's three blocking findings on 86a4694. The public contracts
are now closed shapes rather than descriptions of shapes, run identity has one
spelling, and the two terminal paths are separate everywhere.
Finding 1 — exact bindings and durable records. specs/workflow-workspace-spec.md
is the normative schema location for every authored construct: §7.8 defines the
`GitMergeResult` clean/conflicted union, the conflict-entry record, its sorting,
duplicate and missing-side rules, and restoration failure; §7.9 defines the
`Git.PublishTarget` request and result with five exhaustive pre-states; §7.10
defines the comment request/result and how an engine-derived effect identity is
made remotely observable without using body text, plus literal `Ready`/`Close`
bindings; §10.3 does the same for `Issue.Comment` and `Issue.Close`; §10.5
settles `Evidence.Run` — the whole list runs, separate bounded stdout and stderr
with stated truncation, and an explicit table of which cases bind, which fail
and which commit nothing, with cancellation and teardown precedence fixed; §10.6
defines `Project.Status`. The factory specification §11.2 defines the versioned
closed factory protocol schemas — subject, stage, revision, handoff, actor,
outcome, invalidation, verdicts, conflict suspension, Stage 7 decisions, the
frontier and its complete reduction table, and the two asymmetric terminals.
Finding 1 also adds `PullRequest.Merged` (§7.11), the reconciled Git-host
observation that owns the post-publication merged fact, and settles the remote
host boundary (§13.2): the existing four-method `WorkflowHost` stays the host
assembly contract with a Cloudflare implementation beside the Deno one, the
runner-to-owner transport is a closed versioned envelope that refuses rather
than adapts, and an ownership table says which side owns each concern.
Finding 2 — every restatement of the run-ID derivation now uses `canonical
GitHub authority` byte for byte; the undefined Issue-provider spelling is gone.
Finding 3 — architecture.md and the factory specification now state the merged
and abandoned paths as separate ordered step lists, and the terminal record's
two shapes differ exactly as the paths do, so neither can be read as requiring
the other's effects.
Inventories, evidence tiers and the acceptance checklist are reconciled with all
of it. Documentation only; the ownership SVG is untouched.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SP9dEis51dcwBnwdaXZQAg
Apply rulings A-K from the Architect's answers on 80884f9.
A. Keep the four-method `WorkflowHost` and add that its transition and request
types — `WorkflowExecutionTransitions`, `WorkflowBeginRequest`,
`WorkflowExecutionBegun`, `WorkflowForkRequest`, `WorkflowForkSelection`,
`WorkflowRunCreation` — are provider-neutral and become package-root public
types, with runtime-named entrypoints keeping implementations and retained
encodings. Recorded as authorized future export work, not performed here.
B. `Evidence.Run` becomes an ordered fail-fast pipeline binding the executed
prefix: `{ completion, authoredCommands, executed, runTimeout? }`, rows carrying
`limit` for whichever of the two host-owned ceilings fired, a `runTimeout`
record for a whole-run expiry between commands rather than a fabricated argv
row, timeouts as ordinary unsuccessful outcomes, and fixed precedence —
cancellation over everything, first infrastructure failure authoritative with a
later teardown failure as secondary evidence, teardown authoritative alone —
with bounded diagnostic evidence retained on a failed effect's Error.
C. A comment provider must support a stable opaque correlation marker or refuse
before its first mutation. The authored logical body is preserved byte for byte
and the correlation representation rides outside it. Absence is now judged
against attempt state: no marker after an attempted-but-uncommitted creation is
permanent ambiguity, not proven absence.
D. `PullRequest.Merged` splits still-open (temporary unavailability) from
closed-unmerged (conflict), and the factory gains §10.4 — a bounded
host-configured retry, then a durable machine wait with its own protocol record,
woken by intake or an explicit resume and carrying no verdict.
E. A configured total bijection between the nine stages and nine exact Project
status option IDs, validated against a complete reread and refusing before any
intake, token, run or projection.
F. `Git.Merge`'s `purpose` is validated authorization against the
provider-authenticated merge ceiling, not write-only provenance.
G. The `RunnerRequest` envelope is deleted. The runner and owner ship as one
release identity checked by build fingerprint at admission; the messages are
private, while the owner-side authority invariants stay public and exact.
H. `FactoryTerminal` keeps journal event references, with cross-path, kind,
completeness and agreement validation spelled out.
I. The factory protocol schemas stay in the factory specification §11.2; the
other four documents link rather than duplicate.
J/K. Mixed wrapping left alone, new prose unwrapped; the tenth construct is
reflected everywhere.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SP9dEis51dcwBnwdaXZQAg
taras#710)
Ruling C asked for the comment contracts, the architecture, the WGE evidence and
the generic external-effect explanation to agree. The first three landed in
0d08dcc; §10.2 did not.
Split the two kinds of reconciled effect where the difference actually lives.
An effect that mutates a subject already there — Push, a numbered pull-request
update, ready, close, issue close, Project status — reads that subject, and a
complete observation is decisive whether or not the effect has attempted
anything. An effect that creates a new object the host names has nothing
pre-existing to read and no client-supplied idempotency key, so its completion
is visible only through a correlation value it wrote itself, and absence means a
different thing before and after a mutation has been attempted.
Only the second kind carries attempt state, and it narrows the decision in one
place: unattempted with nothing found performs once, while attempted with no
committed completion and nothing found is permanent ambiguity rather than
absence. A provider that cannot write, preserve and completely query such a
value refuses the effect from observation.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SP9dEis51dcwBnwdaXZQAg
Four narrow corrections from the Architect's verdict on b364b98.
1. The merged-observation wait is not a typed-answer suspension. A machine wait
is a second durable wait kind inside the existing lifecycle: it asks nobody
anything and ends because a later execution observed a provider again, so it
has no response schema, no `xmd workflow answer` route, no form and no bound
value, and it publishes no `suspension_request` and consumes no
`suspension_answer`. It shares only the atomic boundary — its `machine_wait`
event and the `suspended` status commit together, and the acquisition is
released after that commit. Its identity is a `waitId`, never a suspension ID;
`MergedObservationWait.suspensionId` becomes `waitId`, while
`ConflictSuspension.suspensionId` and the typed-answer protocol are untouched.
A new `MergedObservationWake` names the same `waitId` and a closed `source`,
with `intakeId` required exactly for a provider intake and absent exactly for
an operator resume. Waking is permission to look again: the intake retains a
bounded notification carrying no answer, verdict, stage, transition or
observation result, a later executor consumes it and appends the wake event in
one transaction, and a resume without a pending wake or operator authority
reports the same wait and settles suspended again.
2. The generic create-effect rule now distinguishes its two safe mechanisms. An
effect with a provider-native client key — an Issue upsert, a pull-request
upsert — reconciles on that key and carries no attempt state; creating an
object is not by itself what makes an effect attempt-stateful. A comment has
neither a native key nor a pre-existing subject, which is why it needs the
marker and the unattempted/attempted distinction. An effect with neither
mechanism refuses before its first mutation, as an intentional constraint.
3. Completed replay may reach and read the run's durable owner — lifecycle
storage access, not external-effect replay — while attaching no external-effect
provider, performing no effect again and starting no native operation. The
"no remote storage session" wording is gone from every document.
4. The authored comment body is preserved byte for byte as the authored portion
of the projection, with transport metadata outside it, rather than the provider
payload being claimed to equal the authored bytes.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SP9dEis51dcwBnwdaXZQAg
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@minkimcello
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

🏭 Complete the software-factory contract above PR #630 - #736

Open
minkimcello wants to merge 5 commits into
taras:codex/github-actions-software-factory-architecturefrom
minkimcello:claude/710-software-factory-contract
Open

🏭 Complete the software-factory contract above PR #630#736
minkimcello wants to merge 5 commits into
taras:codex/github-actions-software-factory-architecturefrom
minkimcello:claude/710-software-factory-contract

Conversation

@minkimcello

Copy link
Copy Markdown

Why

Closes#710.

The implementation stories under #633 need one decision-complete software-factory contract before they can build provider, ingress, Git, evidence, and factory behavior without choosing architecture independently. This PR completes that contract on top of the draft architecture in #630.

What changes

Before:

The draft architecture left deployment ownership, conflict behavior, durable identity, authority, target publication, replay, and terminal outcomes incomplete or distributed across documents.

After:

The architecture and specifications define the Cloudflare Durable Object owner, connection-scoped executor acquisition, GitHub intake and permission boundaries, stable run and effect identities, exact Git and target-publication behavior, machine waits, reconciliation, replay, abandonment, and the public construct inventory consumed by F1–F6.

How it works

GitHub intake and Actions execution → one durable run owner → provider-neutral effects and retained lifecycle → exact terminal reconciliation

Review guide

Start with:specs/github-actions-software-factory-spec.md

Then review:

  1. architecture.md for topology, principals, ownership, and durable boundaries.
  2. specs/workflow-spec.md for provider-neutral lifecycle and host contracts.
  3. specs/workflow-workspace-spec.md for effect, wait, reconciliation, and replay semantics.
  4. specs/executable-mdx-spec.md for the frozen conformance inventory.

Look carefully at:

  • The separation between typed-answer suspensions and provider-state machine waits.
  • Connection-scoped executor authority and transaction ownership.
  • Idempotency, attempt-state ambiguity, and completed replay without external-provider attachment.

What must stay true

  • One Durable Object owns one run's durable state; ephemeral runners own Git, evidence processes, and Agent clients.
  • Every protected mutation validates the live acquisition and expected Workspace root in its transaction.
  • External effects reconcile through their specified natural keys and fail closed on ambiguous attempted creation.
  • Completed replay reads only the durable owner and performs no external effect again.

How to verify it

Scope

Included

Intentionally unchanged

Risks and limitations

  • This PR is stacked on PR 🏭 Specify the GitHub Actions-hosted AI software factory #630. Descendant implementation branches must use accepted commit 817d3dd36cb07fddd972c6ae33716444f3cb75da as their exact contract base and be reconciled if that contract changes.
  • Recovery: amend this contract explicitly and restack affected descendants; do not repair structural omissions privately in an implementation PR.

Scope confirmation

  • Every changed file supports the purpose described above.
  • Unrelated cleanup and formatting changes are excluded.
  • Generated or mechanical changes are clearly identified.
  • The description matches the final diff and test results.

minkimcelloand others added 5 commits September 2, 2026 09:33
Turn PR taras#630's draft into a decision-complete first-release architecture. No
product, deployment, authority, identity, ownership, failure, replay, public
form, permission or ordering decision is left for a later Implementor.
The factory specification now settles: the canonical `github-issue-v1` run-ID
derivation and unsupported issue-transfer drift; `User` as the only Stage 1
spelling; the deployment topology of one SQLite-backed Cloudflare Durable
Object, an authenticated executor WebSocket, an ephemeral Actions runner and a
dedicated GitHub App; authenticated ingress order, bounded intake, dispatch
payload and OIDC claims; the exact App permissions, host ceilings, human
permission floor and `.github/workflows/**` denial; suspend-on-every-conflict
as the single Stage 4 profile; the Stage 7 trusted merge, `Git.PublishTarget`
compare-and-swap and remote-effect-before-terminal ordering; and the exact
public contract inventory. Section 8's remaining material decisions are gone.
architecture.md gains the terminology, the remote storage and executor
topology, the delivery-plane generalization, the Project-provider boundary,
comments/readiness/closure, ordered merge, target publication, trusted evidence
execution, terminal settlement, the split trusted host, and ten construct
inventory rows marked "specified by taras#710; implementation unbuilt".
The workflow and Workspace specifications gain the remote host, the executor
connection, which requests need it and which do not, the host-derived public
run ID, and provider-neutral contracts for `Git.Merge`, `Git.PublishTarget`,
`PullRequest.Comment`/`Ready`/`Close`, `Issue.Comment`/`Close`, `Evidence.Run`
and `Project.Status` — none of them reachable by an Agent or generated XMD,
whose write table stays exactly `File:write`, `Dir` and `File.Delete`. The
executable-MDX specification gains the exact authored forms and the frozen
WRH/WGI/WGE/WGM/WER/WFP/WFL acceptance tiers.
Documentation only: no production code, workflow YAML, dependency, generated
artifact or executable fixture changes, and the ownership SVG already agrees
with the amended text.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SP9dEis51dcwBnwdaXZQAg
Answer the Architect's three blocking findings on 86a4694. The public contracts
are now closed shapes rather than descriptions of shapes, run identity has one
spelling, and the two terminal paths are separate everywhere.
Finding 1 — exact bindings and durable records. specs/workflow-workspace-spec.md
is the normative schema location for every authored construct: §7.8 defines the
`GitMergeResult` clean/conflicted union, the conflict-entry record, its sorting,
duplicate and missing-side rules, and restoration failure; §7.9 defines the
`Git.PublishTarget` request and result with five exhaustive pre-states; §7.10
defines the comment request/result and how an engine-derived effect identity is
made remotely observable without using body text, plus literal `Ready`/`Close`
bindings; §10.3 does the same for `Issue.Comment` and `Issue.Close`; §10.5
settles `Evidence.Run` — the whole list runs, separate bounded stdout and stderr
with stated truncation, and an explicit table of which cases bind, which fail
and which commit nothing, with cancellation and teardown precedence fixed; §10.6
defines `Project.Status`. The factory specification §11.2 defines the versioned
closed factory protocol schemas — subject, stage, revision, handoff, actor,
outcome, invalidation, verdicts, conflict suspension, Stage 7 decisions, the
frontier and its complete reduction table, and the two asymmetric terminals.
Finding 1 also adds `PullRequest.Merged` (§7.11), the reconciled Git-host
observation that owns the post-publication merged fact, and settles the remote
host boundary (§13.2): the existing four-method `WorkflowHost` stays the host
assembly contract with a Cloudflare implementation beside the Deno one, the
runner-to-owner transport is a closed versioned envelope that refuses rather
than adapts, and an ownership table says which side owns each concern.
Finding 2 — every restatement of the run-ID derivation now uses `canonical
GitHub authority` byte for byte; the undefined Issue-provider spelling is gone.
Finding 3 — architecture.md and the factory specification now state the merged
and abandoned paths as separate ordered step lists, and the terminal record's
two shapes differ exactly as the paths do, so neither can be read as requiring
the other's effects.
Inventories, evidence tiers and the acceptance checklist are reconciled with all
of it. Documentation only; the ownership SVG is untouched.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SP9dEis51dcwBnwdaXZQAg
Apply rulings A-K from the Architect's answers on 80884f9.
A. Keep the four-method `WorkflowHost` and add that its transition and request
types — `WorkflowExecutionTransitions`, `WorkflowBeginRequest`,
`WorkflowExecutionBegun`, `WorkflowForkRequest`, `WorkflowForkSelection`,
`WorkflowRunCreation` — are provider-neutral and become package-root public
types, with runtime-named entrypoints keeping implementations and retained
encodings. Recorded as authorized future export work, not performed here.
B. `Evidence.Run` becomes an ordered fail-fast pipeline binding the executed
prefix: `{ completion, authoredCommands, executed, runTimeout? }`, rows carrying
`limit` for whichever of the two host-owned ceilings fired, a `runTimeout`
record for a whole-run expiry between commands rather than a fabricated argv
row, timeouts as ordinary unsuccessful outcomes, and fixed precedence —
cancellation over everything, first infrastructure failure authoritative with a
later teardown failure as secondary evidence, teardown authoritative alone —
with bounded diagnostic evidence retained on a failed effect's Error.
C. A comment provider must support a stable opaque correlation marker or refuse
before its first mutation. The authored logical body is preserved byte for byte
and the correlation representation rides outside it. Absence is now judged
against attempt state: no marker after an attempted-but-uncommitted creation is
permanent ambiguity, not proven absence.
D. `PullRequest.Merged` splits still-open (temporary unavailability) from
closed-unmerged (conflict), and the factory gains §10.4 — a bounded
host-configured retry, then a durable machine wait with its own protocol record,
woken by intake or an explicit resume and carrying no verdict.
E. A configured total bijection between the nine stages and nine exact Project
status option IDs, validated against a complete reread and refusing before any
intake, token, run or projection.
F. `Git.Merge`'s `purpose` is validated authorization against the
provider-authenticated merge ceiling, not write-only provenance.
G. The `RunnerRequest` envelope is deleted. The runner and owner ship as one
release identity checked by build fingerprint at admission; the messages are
private, while the owner-side authority invariants stay public and exact.
H. `FactoryTerminal` keeps journal event references, with cross-path, kind,
completeness and agreement validation spelled out.
I. The factory protocol schemas stay in the factory specification §11.2; the
other four documents link rather than duplicate.
J/K. Mixed wrapping left alone, new prose unwrapped; the tenth construct is
reflected everywhere.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SP9dEis51dcwBnwdaXZQAg
taras#710)
Ruling C asked for the comment contracts, the architecture, the WGE evidence and
the generic external-effect explanation to agree. The first three landed in
0d08dcc; §10.2 did not.
Split the two kinds of reconciled effect where the difference actually lives.
An effect that mutates a subject already there — Push, a numbered pull-request
update, ready, close, issue close, Project status — reads that subject, and a
complete observation is decisive whether or not the effect has attempted
anything. An effect that creates a new object the host names has nothing
pre-existing to read and no client-supplied idempotency key, so its completion
is visible only through a correlation value it wrote itself, and absence means a
different thing before and after a mutation has been attempted.
Only the second kind carries attempt state, and it narrows the decision in one
place: unattempted with nothing found performs once, while attempted with no
committed completion and nothing found is permanent ambiguity rather than
absence. A provider that cannot write, preserve and completely query such a
value refuses the effect from observation.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SP9dEis51dcwBnwdaXZQAg
Four narrow corrections from the Architect's verdict on b364b98.
1. The merged-observation wait is not a typed-answer suspension. A machine wait
is a second durable wait kind inside the existing lifecycle: it asks nobody
anything and ends because a later execution observed a provider again, so it
has no response schema, no `xmd workflow answer` route, no form and no bound
value, and it publishes no `suspension_request` and consumes no
`suspension_answer`. It shares only the atomic boundary — its `machine_wait`
event and the `suspended` status commit together, and the acquisition is
released after that commit. Its identity is a `waitId`, never a suspension ID;
`MergedObservationWait.suspensionId` becomes `waitId`, while
`ConflictSuspension.suspensionId` and the typed-answer protocol are untouched.
A new `MergedObservationWake` names the same `waitId` and a closed `source`,
with `intakeId` required exactly for a provider intake and absent exactly for
an operator resume. Waking is permission to look again: the intake retains a
bounded notification carrying no answer, verdict, stage, transition or
observation result, a later executor consumes it and appends the wake event in
one transaction, and a resume without a pending wake or operator authority
reports the same wait and settles suspended again.
2. The generic create-effect rule now distinguishes its two safe mechanisms. An
effect with a provider-native client key — an Issue upsert, a pull-request
upsert — reconciles on that key and carries no attempt state; creating an
object is not by itself what makes an effect attempt-stateful. A comment has
neither a native key nor a pre-existing subject, which is why it needs the
marker and the unattempted/attempted distinction. An effect with neither
mechanism refuses before its first mutation, as an intentional constraint.
3. Completed replay may reach and read the run's durable owner — lifecycle
storage access, not external-effect replay — while attaching no external-effect
provider, performing no effect again and starting no native operation. The
"no remote storage session" wording is gone from every document.
4. The authored comment body is preserved byte for byte as the authored portion
of the projection, with transport metadata outside it, rather than the provider
payload being claimed to equal the authored bytes.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SP9dEis51dcwBnwdaXZQAg
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@minkimcello
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

🏭 Complete the software-factory contract above PR #630 - #736

Open
minkimcello wants to merge 5 commits into
taras:codex/github-actions-software-factory-architecturefrom
minkimcello:claude/710-software-factory-contract
Open

🏭 Complete the software-factory contract above PR #630#736
minkimcello wants to merge 5 commits into
taras:codex/github-actions-software-factory-architecturefrom
minkimcello:claude/710-software-factory-contract

Conversation

@minkimcello

Copy link
Copy Markdown

Why

Closes#710.

The implementation stories under #633 need one decision-complete software-factory contract before they can build provider, ingress, Git, evidence, and factory behavior without choosing architecture independently. This PR completes that contract on top of the draft architecture in #630.

What changes

Before:

The draft architecture left deployment ownership, conflict behavior, durable identity, authority, target publication, replay, and terminal outcomes incomplete or distributed across documents.

After:

The architecture and specifications define the Cloudflare Durable Object owner, connection-scoped executor acquisition, GitHub intake and permission boundaries, stable run and effect identities, exact Git and target-publication behavior, machine waits, reconciliation, replay, abandonment, and the public construct inventory consumed by F1–F6.

How it works

GitHub intake and Actions execution → one durable run owner → provider-neutral effects and retained lifecycle → exact terminal reconciliation

Review guide

Start with:specs/github-actions-software-factory-spec.md

Then review:

  1. architecture.md for topology, principals, ownership, and durable boundaries.
  2. specs/workflow-spec.md for provider-neutral lifecycle and host contracts.
  3. specs/workflow-workspace-spec.md for effect, wait, reconciliation, and replay semantics.
  4. specs/executable-mdx-spec.md for the frozen conformance inventory.

Look carefully at:

  • The separation between typed-answer suspensions and provider-state machine waits.
  • Connection-scoped executor authority and transaction ownership.
  • Idempotency, attempt-state ambiguity, and completed replay without external-provider attachment.

What must stay true

  • One Durable Object owns one run's durable state; ephemeral runners own Git, evidence processes, and Agent clients.
  • Every protected mutation validates the live acquisition and expected Workspace root in its transaction.
  • External effects reconcile through their specified natural keys and fail closed on ambiguous attempted creation.
  • Completed replay reads only the durable owner and performs no external effect again.

How to verify it

Scope

Included

Intentionally unchanged

Risks and limitations

  • This PR is stacked on PR 🏭 Specify the GitHub Actions-hosted AI software factory #630. Descendant implementation branches must use accepted commit 817d3dd36cb07fddd972c6ae33716444f3cb75da as their exact contract base and be reconciled if that contract changes.
  • Recovery: amend this contract explicitly and restack affected descendants; do not repair structural omissions privately in an implementation PR.

Scope confirmation

  • Every changed file supports the purpose described above.
  • Unrelated cleanup and formatting changes are excluded.
  • Generated or mechanical changes are clearly identified.
  • The description matches the final diff and test results.

minkimcelloand others added 5 commits September 2, 2026 09:33
Turn PR taras#630's draft into a decision-complete first-release architecture. No
product, deployment, authority, identity, ownership, failure, replay, public
form, permission or ordering decision is left for a later Implementor.
The factory specification now settles: the canonical `github-issue-v1` run-ID
derivation and unsupported issue-transfer drift; `User` as the only Stage 1
spelling; the deployment topology of one SQLite-backed Cloudflare Durable
Object, an authenticated executor WebSocket, an ephemeral Actions runner and a
dedicated GitHub App; authenticated ingress order, bounded intake, dispatch
payload and OIDC claims; the exact App permissions, host ceilings, human
permission floor and `.github/workflows/**` denial; suspend-on-every-conflict
as the single Stage 4 profile; the Stage 7 trusted merge, `Git.PublishTarget`
compare-and-swap and remote-effect-before-terminal ordering; and the exact
public contract inventory. Section 8's remaining material decisions are gone.
architecture.md gains the terminology, the remote storage and executor
topology, the delivery-plane generalization, the Project-provider boundary,
comments/readiness/closure, ordered merge, target publication, trusted evidence
execution, terminal settlement, the split trusted host, and ten construct
inventory rows marked "specified by taras#710; implementation unbuilt".
The workflow and Workspace specifications gain the remote host, the executor
connection, which requests need it and which do not, the host-derived public
run ID, and provider-neutral contracts for `Git.Merge`, `Git.PublishTarget`,
`PullRequest.Comment`/`Ready`/`Close`, `Issue.Comment`/`Close`, `Evidence.Run`
and `Project.Status` — none of them reachable by an Agent or generated XMD,
whose write table stays exactly `File:write`, `Dir` and `File.Delete`. The
executable-MDX specification gains the exact authored forms and the frozen
WRH/WGI/WGE/WGM/WER/WFP/WFL acceptance tiers.
Documentation only: no production code, workflow YAML, dependency, generated
artifact or executable fixture changes, and the ownership SVG already agrees
with the amended text.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SP9dEis51dcwBnwdaXZQAg
Answer the Architect's three blocking findings on 86a4694. The public contracts
are now closed shapes rather than descriptions of shapes, run identity has one
spelling, and the two terminal paths are separate everywhere.
Finding 1 — exact bindings and durable records. specs/workflow-workspace-spec.md
is the normative schema location for every authored construct: §7.8 defines the
`GitMergeResult` clean/conflicted union, the conflict-entry record, its sorting,
duplicate and missing-side rules, and restoration failure; §7.9 defines the
`Git.PublishTarget` request and result with five exhaustive pre-states; §7.10
defines the comment request/result and how an engine-derived effect identity is
made remotely observable without using body text, plus literal `Ready`/`Close`
bindings; §10.3 does the same for `Issue.Comment` and `Issue.Close`; §10.5
settles `Evidence.Run` — the whole list runs, separate bounded stdout and stderr
with stated truncation, and an explicit table of which cases bind, which fail
and which commit nothing, with cancellation and teardown precedence fixed; §10.6
defines `Project.Status`. The factory specification §11.2 defines the versioned
closed factory protocol schemas — subject, stage, revision, handoff, actor,
outcome, invalidation, verdicts, conflict suspension, Stage 7 decisions, the
frontier and its complete reduction table, and the two asymmetric terminals.
Finding 1 also adds `PullRequest.Merged` (§7.11), the reconciled Git-host
observation that owns the post-publication merged fact, and settles the remote
host boundary (§13.2): the existing four-method `WorkflowHost` stays the host
assembly contract with a Cloudflare implementation beside the Deno one, the
runner-to-owner transport is a closed versioned envelope that refuses rather
than adapts, and an ownership table says which side owns each concern.
Finding 2 — every restatement of the run-ID derivation now uses `canonical
GitHub authority` byte for byte; the undefined Issue-provider spelling is gone.
Finding 3 — architecture.md and the factory specification now state the merged
and abandoned paths as separate ordered step lists, and the terminal record's
two shapes differ exactly as the paths do, so neither can be read as requiring
the other's effects.
Inventories, evidence tiers and the acceptance checklist are reconciled with all
of it. Documentation only; the ownership SVG is untouched.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SP9dEis51dcwBnwdaXZQAg
Apply rulings A-K from the Architect's answers on 80884f9.
A. Keep the four-method `WorkflowHost` and add that its transition and request
types — `WorkflowExecutionTransitions`, `WorkflowBeginRequest`,
`WorkflowExecutionBegun`, `WorkflowForkRequest`, `WorkflowForkSelection`,
`WorkflowRunCreation` — are provider-neutral and become package-root public
types, with runtime-named entrypoints keeping implementations and retained
encodings. Recorded as authorized future export work, not performed here.
B. `Evidence.Run` becomes an ordered fail-fast pipeline binding the executed
prefix: `{ completion, authoredCommands, executed, runTimeout? }`, rows carrying
`limit` for whichever of the two host-owned ceilings fired, a `runTimeout`
record for a whole-run expiry between commands rather than a fabricated argv
row, timeouts as ordinary unsuccessful outcomes, and fixed precedence —
cancellation over everything, first infrastructure failure authoritative with a
later teardown failure as secondary evidence, teardown authoritative alone —
with bounded diagnostic evidence retained on a failed effect's Error.
C. A comment provider must support a stable opaque correlation marker or refuse
before its first mutation. The authored logical body is preserved byte for byte
and the correlation representation rides outside it. Absence is now judged
against attempt state: no marker after an attempted-but-uncommitted creation is
permanent ambiguity, not proven absence.
D. `PullRequest.Merged` splits still-open (temporary unavailability) from
closed-unmerged (conflict), and the factory gains §10.4 — a bounded
host-configured retry, then a durable machine wait with its own protocol record,
woken by intake or an explicit resume and carrying no verdict.
E. A configured total bijection between the nine stages and nine exact Project
status option IDs, validated against a complete reread and refusing before any
intake, token, run or projection.
F. `Git.Merge`'s `purpose` is validated authorization against the
provider-authenticated merge ceiling, not write-only provenance.
G. The `RunnerRequest` envelope is deleted. The runner and owner ship as one
release identity checked by build fingerprint at admission; the messages are
private, while the owner-side authority invariants stay public and exact.
H. `FactoryTerminal` keeps journal event references, with cross-path, kind,
completeness and agreement validation spelled out.
I. The factory protocol schemas stay in the factory specification §11.2; the
other four documents link rather than duplicate.
J/K. Mixed wrapping left alone, new prose unwrapped; the tenth construct is
reflected everywhere.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SP9dEis51dcwBnwdaXZQAg
taras#710)
Ruling C asked for the comment contracts, the architecture, the WGE evidence and
the generic external-effect explanation to agree. The first three landed in
0d08dcc; §10.2 did not.
Split the two kinds of reconciled effect where the difference actually lives.
An effect that mutates a subject already there — Push, a numbered pull-request
update, ready, close, issue close, Project status — reads that subject, and a
complete observation is decisive whether or not the effect has attempted
anything. An effect that creates a new object the host names has nothing
pre-existing to read and no client-supplied idempotency key, so its completion
is visible only through a correlation value it wrote itself, and absence means a
different thing before and after a mutation has been attempted.
Only the second kind carries attempt state, and it narrows the decision in one
place: unattempted with nothing found performs once, while attempted with no
committed completion and nothing found is permanent ambiguity rather than
absence. A provider that cannot write, preserve and completely query such a
value refuses the effect from observation.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SP9dEis51dcwBnwdaXZQAg
Four narrow corrections from the Architect's verdict on b364b98.
1. The merged-observation wait is not a typed-answer suspension. A machine wait
is a second durable wait kind inside the existing lifecycle: it asks nobody
anything and ends because a later execution observed a provider again, so it
has no response schema, no `xmd workflow answer` route, no form and no bound
value, and it publishes no `suspension_request` and consumes no
`suspension_answer`. It shares only the atomic boundary — its `machine_wait`
event and the `suspended` status commit together, and the acquisition is
released after that commit. Its identity is a `waitId`, never a suspension ID;
`MergedObservationWait.suspensionId` becomes `waitId`, while
`ConflictSuspension.suspensionId` and the typed-answer protocol are untouched.
A new `MergedObservationWake` names the same `waitId` and a closed `source`,
with `intakeId` required exactly for a provider intake and absent exactly for
an operator resume. Waking is permission to look again: the intake retains a
bounded notification carrying no answer, verdict, stage, transition or
observation result, a later executor consumes it and appends the wake event in
one transaction, and a resume without a pending wake or operator authority
reports the same wait and settles suspended again.
2. The generic create-effect rule now distinguishes its two safe mechanisms. An
effect with a provider-native client key — an Issue upsert, a pull-request
upsert — reconciles on that key and carries no attempt state; creating an
object is not by itself what makes an effect attempt-stateful. A comment has
neither a native key nor a pre-existing subject, which is why it needs the
marker and the unattempted/attempted distinction. An effect with neither
mechanism refuses before its first mutation, as an intentional constraint.
3. Completed replay may reach and read the run's durable owner — lifecycle
storage access, not external-effect replay — while attaching no external-effect
provider, performing no effect again and starting no native operation. The
"no remote storage session" wording is gone from every document.
4. The authored comment body is preserved byte for byte as the authored portion
of the projection, with transport metadata outside it, rather than the provider
payload being claimed to equal the authored bytes.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SP9dEis51dcwBnwdaXZQAg
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@minkimcello