Add contextual workflow runs with pinned commits #289

Description

@taras

Story

As a workflow author, I want each workflow run tied to one pinned starting commit and each executable element identified deterministically, so durable records and effects have explicit identities without extending execution lifetimes.

Scope

Add Expansion and getExpansion() to @executablemd/core. Introduce @executablemd/workflow with WorkflowRun, useWorkflow({ base }), getWorkflowRun(), and the contextual Git.revParse() capability.

getExpansion() replaces the public invocation() metadata reader without an alias. Private invocation lifecycle machinery remains internal.

WorkflowRun contains:

  • runId — an opaque stable identifier;
  • base — the supplied Git revision; and
  • pinnedCommit — the commit obtained by resolving the base once.

Git.revParse() has the semantics of:

git rev-parse --verify --end-of-options <revision>

The workflow package depends on @executablemd/core, @executablemd/durable-streams, and @executablemd/runtime. Core never imports workflow or Git.

Workflow-run lifetime

useWorkflow() installs ordinary middleware in the child scope that owns one document execution. Installing it alone creates no workflow run.

The first durable operation:

  1. allocates a cryptographically random run ID;
  2. resolves base^{commit} through Git.revParse();
  3. records one immutable WorkflowRun before root import.

getWorkflowRun() is available only inside the associated document execution. It throws:

  • before execute() starts;
  • when execute() has no useWorkflow() installation; and
  • after that document execution completes, even while the installer scope still exists.

Concurrent document executions remain isolated through Effection scope ownership.

Replay

Replay restores the recorded WorkflowRun without allocating another run ID or invoking Git. The supplied base must equal the recorded base. A completed journal must restore workflow metadata before the root-close shortcut, and a malformed record is refused rather than coerced.

Expansion identity

Expansion reports id, authored name, and opening-tag source position when known. Its ID derives from root document and structural expansion path, never from process-global state, time, randomness, scheduling order, or run ID.

Replay, retry attempts, and restoration of the same loop iteration preserve the ID. Distinct authored elements, loop iterations, projections, component expansions, and root documents receive distinct IDs.

Acceptance

  • Every descendant observes one frozen WorkflowRun by reference during a live document execution.
  • getWorkflowRun() obeys the exact before/during/after lifetime above.
  • Replay invokes neither run-ID allocation nor Git and refuses a changed base.
  • Git failures occur before root import and record no successful WorkflowRun.
  • Ordinary execute() and xmd run remain Git-independent without workflow middleware.
  • getExpansion() throws outside an executable element expansion and exposes no props, bindings, selected component, projected content, or live scope.
  • Expansion IDs satisfy every determinism and distinction claim above.
  • Workflow-wide durable identity combines run ID and expansion ID; the expansion ID does not embed the run ID.
  • Tests discriminate scope, derivation, replay, and Git-resolution boundaries.

Intentionally excluded

Dependencies

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions

      , 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all \u003cpre\u003e\u003ccode\u003e 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

      Add contextual workflow runs with pinned commits #289

      Description

      @taras

      Story

      As a workflow author, I want each workflow run tied to one pinned starting commit and each executable element identified deterministically, so durable records and effects have explicit identities without extending execution lifetimes.

      Scope

      Add Expansion and getExpansion() to @executablemd/core. Introduce @executablemd/workflow with WorkflowRun, useWorkflow({ base }), getWorkflowRun(), and the contextual Git.revParse() capability.

      getExpansion() replaces the public invocation() metadata reader without an alias. Private invocation lifecycle machinery remains internal.

      WorkflowRun contains:

      • runId — an opaque stable identifier;
      • base — the supplied Git revision; and
      • pinnedCommit — the commit obtained by resolving the base once.

      Git.revParse() has the semantics of:

      git rev-parse --verify --end-of-options <revision>
      

      The workflow package depends on @executablemd/core, @executablemd/durable-streams, and @executablemd/runtime. Core never imports workflow or Git.

      Workflow-run lifetime

      useWorkflow() installs ordinary middleware in the child scope that owns one document execution. Installing it alone creates no workflow run.

      The first durable operation:

      1. allocates a cryptographically random run ID;
      2. resolves base^{commit} through Git.revParse();
      3. records one immutable WorkflowRun before root import.

      getWorkflowRun() is available only inside the associated document execution. It throws:

      • before execute() starts;
      • when execute() has no useWorkflow() installation; and
      • after that document execution completes, even while the installer scope still exists.

      Concurrent document executions remain isolated through Effection scope ownership.

      Replay

      Replay restores the recorded WorkflowRun without allocating another run ID or invoking Git. The supplied base must equal the recorded base. A completed journal must restore workflow metadata before the root-close shortcut, and a malformed record is refused rather than coerced.

      Expansion identity

      Expansion reports id, authored name, and opening-tag source position when known. Its ID derives from root document and structural expansion path, never from process-global state, time, randomness, scheduling order, or run ID.

      Replay, retry attempts, and restoration of the same loop iteration preserve the ID. Distinct authored elements, loop iterations, projections, component expansions, and root documents receive distinct IDs.

      Acceptance

      • Every descendant observes one frozen WorkflowRun by reference during a live document execution.
      • getWorkflowRun() obeys the exact before/during/after lifetime above.
      • Replay invokes neither run-ID allocation nor Git and refuses a changed base.
      • Git failures occur before root import and record no successful WorkflowRun.
      • Ordinary execute() and xmd run remain Git-independent without workflow middleware.
      • getExpansion() throws outside an executable element expansion and exposes no props, bindings, selected component, projected content, or live scope.
      • Expansion IDs satisfy every determinism and distinction claim above.
      • Workflow-wide durable identity combines run ID and expansion ID; the expansion ID does not embed the run ID.
      • Tests discriminate scope, derivation, replay, and Git-resolution boundaries.

      Intentionally excluded

      Dependencies

      Activity

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

      Metadata

      Metadata

      Assignees

      No one assigned

        Labels

        No labels
        No labels

        Projects

        No projects

          Relationships

          None yet

          Development

          No branches or pull requests

          Issue actions

          , '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

          Add contextual workflow runs with pinned commits #289

          Description

          @taras

          Story

          As a workflow author, I want each workflow run tied to one pinned starting commit and each executable element identified deterministically, so durable records and effects have explicit identities without extending execution lifetimes.

          Scope

          Add Expansion and getExpansion() to @executablemd/core. Introduce @executablemd/workflow with WorkflowRun, useWorkflow({ base }), getWorkflowRun(), and the contextual Git.revParse() capability.

          getExpansion() replaces the public invocation() metadata reader without an alias. Private invocation lifecycle machinery remains internal.

          WorkflowRun contains:

          • runId — an opaque stable identifier;
          • base — the supplied Git revision; and
          • pinnedCommit — the commit obtained by resolving the base once.

          Git.revParse() has the semantics of:

          git rev-parse --verify --end-of-options <revision>
          

          The workflow package depends on @executablemd/core, @executablemd/durable-streams, and @executablemd/runtime. Core never imports workflow or Git.

          Workflow-run lifetime

          useWorkflow() installs ordinary middleware in the child scope that owns one document execution. Installing it alone creates no workflow run.

          The first durable operation:

          1. allocates a cryptographically random run ID;
          2. resolves base^{commit} through Git.revParse();
          3. records one immutable WorkflowRun before root import.

          getWorkflowRun() is available only inside the associated document execution. It throws:

          • before execute() starts;
          • when execute() has no useWorkflow() installation; and
          • after that document execution completes, even while the installer scope still exists.

          Concurrent document executions remain isolated through Effection scope ownership.

          Replay

          Replay restores the recorded WorkflowRun without allocating another run ID or invoking Git. The supplied base must equal the recorded base. A completed journal must restore workflow metadata before the root-close shortcut, and a malformed record is refused rather than coerced.

          Expansion identity

          Expansion reports id, authored name, and opening-tag source position when known. Its ID derives from root document and structural expansion path, never from process-global state, time, randomness, scheduling order, or run ID.

          Replay, retry attempts, and restoration of the same loop iteration preserve the ID. Distinct authored elements, loop iterations, projections, component expansions, and root documents receive distinct IDs.

          Acceptance

          • Every descendant observes one frozen WorkflowRun by reference during a live document execution.
          • getWorkflowRun() obeys the exact before/during/after lifetime above.
          • Replay invokes neither run-ID allocation nor Git and refuses a changed base.
          • Git failures occur before root import and record no successful WorkflowRun.
          • Ordinary execute() and xmd run remain Git-independent without workflow middleware.
          • getExpansion() throws outside an executable element expansion and exposes no props, bindings, selected component, projected content, or live scope.
          • Expansion IDs satisfy every determinism and distinction claim above.
          • Workflow-wide durable identity combines run ID and expansion ID; the expansion ID does not embed the run ID.
          • Tests discriminate scope, derivation, replay, and Git-resolution boundaries.

          Intentionally excluded

          Dependencies

          Activity

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

          Metadata

          Metadata

          Assignees

          No one assigned

            Labels

            No labels
            No labels

            Projects

            No projects

              Relationships

              None yet

              Development

              No branches or pull requests

              Issue actions

              , '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 \u003e 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

              Add contextual workflow runs with pinned commits #289

              Description

              @taras

              Story

              As a workflow author, I want each workflow run tied to one pinned starting commit and each executable element identified deterministically, so durable records and effects have explicit identities without extending execution lifetimes.

              Scope

              Add Expansion and getExpansion() to @executablemd/core. Introduce @executablemd/workflow with WorkflowRun, useWorkflow({ base }), getWorkflowRun(), and the contextual Git.revParse() capability.

              getExpansion() replaces the public invocation() metadata reader without an alias. Private invocation lifecycle machinery remains internal.

              WorkflowRun contains:

              • runId — an opaque stable identifier;
              • base — the supplied Git revision; and
              • pinnedCommit — the commit obtained by resolving the base once.

              Git.revParse() has the semantics of:

              git rev-parse --verify --end-of-options <revision>
              

              The workflow package depends on @executablemd/core, @executablemd/durable-streams, and @executablemd/runtime. Core never imports workflow or Git.

              Workflow-run lifetime

              useWorkflow() installs ordinary middleware in the child scope that owns one document execution. Installing it alone creates no workflow run.

              The first durable operation:

              1. allocates a cryptographically random run ID;
              2. resolves base^{commit} through Git.revParse();
              3. records one immutable WorkflowRun before root import.

              getWorkflowRun() is available only inside the associated document execution. It throws:

              • before execute() starts;
              • when execute() has no useWorkflow() installation; and
              • after that document execution completes, even while the installer scope still exists.

              Concurrent document executions remain isolated through Effection scope ownership.

              Replay

              Replay restores the recorded WorkflowRun without allocating another run ID or invoking Git. The supplied base must equal the recorded base. A completed journal must restore workflow metadata before the root-close shortcut, and a malformed record is refused rather than coerced.

              Expansion identity

              Expansion reports id, authored name, and opening-tag source position when known. Its ID derives from root document and structural expansion path, never from process-global state, time, randomness, scheduling order, or run ID.

              Replay, retry attempts, and restoration of the same loop iteration preserve the ID. Distinct authored elements, loop iterations, projections, component expansions, and root documents receive distinct IDs.

              Acceptance

              • Every descendant observes one frozen WorkflowRun by reference during a live document execution.
              • getWorkflowRun() obeys the exact before/during/after lifetime above.
              • Replay invokes neither run-ID allocation nor Git and refuses a changed base.
              • Git failures occur before root import and record no successful WorkflowRun.
              • Ordinary execute() and xmd run remain Git-independent without workflow middleware.
              • getExpansion() throws outside an executable element expansion and exposes no props, bindings, selected component, projected content, or live scope.
              • Expansion IDs satisfy every determinism and distinction claim above.
              • Workflow-wide durable identity combines run ID and expansion ID; the expansion ID does not embed the run ID.
              • Tests discriminate scope, derivation, replay, and Git-resolution boundaries.

              Intentionally excluded

              Dependencies

              Activity

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

              Metadata

              Metadata

              Assignees

              No one assigned

                Labels

                No labels
                No labels

                Projects

                No projects

                  Relationships

                  None yet

                  Development

                  No branches or pull requests

                  Issue actions

                  , '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

                  Add contextual workflow runs with pinned commits #289

                  Description

                  @taras

                  Story

                  As a workflow author, I want each workflow run tied to one pinned starting commit and each executable element identified deterministically, so durable records and effects have explicit identities without extending execution lifetimes.

                  Scope

                  Add Expansion and getExpansion() to @executablemd/core. Introduce @executablemd/workflow with WorkflowRun, useWorkflow({ base }), getWorkflowRun(), and the contextual Git.revParse() capability.

                  getExpansion() replaces the public invocation() metadata reader without an alias. Private invocation lifecycle machinery remains internal.

                  WorkflowRun contains:

                  • runId — an opaque stable identifier;
                  • base — the supplied Git revision; and
                  • pinnedCommit — the commit obtained by resolving the base once.

                  Git.revParse() has the semantics of:

                  git rev-parse --verify --end-of-options <revision>
                  

                  The workflow package depends on @executablemd/core, @executablemd/durable-streams, and @executablemd/runtime. Core never imports workflow or Git.

                  Workflow-run lifetime

                  useWorkflow() installs ordinary middleware in the child scope that owns one document execution. Installing it alone creates no workflow run.

                  The first durable operation:

                  1. allocates a cryptographically random run ID;
                  2. resolves base^{commit} through Git.revParse();
                  3. records one immutable WorkflowRun before root import.

                  getWorkflowRun() is available only inside the associated document execution. It throws:

                  • before execute() starts;
                  • when execute() has no useWorkflow() installation; and
                  • after that document execution completes, even while the installer scope still exists.

                  Concurrent document executions remain isolated through Effection scope ownership.

                  Replay

                  Replay restores the recorded WorkflowRun without allocating another run ID or invoking Git. The supplied base must equal the recorded base. A completed journal must restore workflow metadata before the root-close shortcut, and a malformed record is refused rather than coerced.

                  Expansion identity

                  Expansion reports id, authored name, and opening-tag source position when known. Its ID derives from root document and structural expansion path, never from process-global state, time, randomness, scheduling order, or run ID.

                  Replay, retry attempts, and restoration of the same loop iteration preserve the ID. Distinct authored elements, loop iterations, projections, component expansions, and root documents receive distinct IDs.

                  Acceptance

                  • Every descendant observes one frozen WorkflowRun by reference during a live document execution.
                  • getWorkflowRun() obeys the exact before/during/after lifetime above.
                  • Replay invokes neither run-ID allocation nor Git and refuses a changed base.
                  • Git failures occur before root import and record no successful WorkflowRun.
                  • Ordinary execute() and xmd run remain Git-independent without workflow middleware.
                  • getExpansion() throws outside an executable element expansion and exposes no props, bindings, selected component, projected content, or live scope.
                  • Expansion IDs satisfy every determinism and distinction claim above.
                  • Workflow-wide durable identity combines run ID and expansion ID; the expansion ID does not embed the run ID.
                  • Tests discriminate scope, derivation, replay, and Git-resolution boundaries.

                  Intentionally excluded

                  Dependencies

                  Activity

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

                  Metadata

                  Metadata

                  Assignees

                  No one assigned

                    Labels

                    No labels
                    No labels

                    Projects

                    No projects

                      Relationships

                      None yet

                      Development

                      No branches or pull requests

                      Issue actions

                      , '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

                      Add contextual workflow runs with pinned commits #289

                      Description

                      @taras

                      Story

                      As a workflow author, I want each workflow run tied to one pinned starting commit and each executable element identified deterministically, so durable records and effects have explicit identities without extending execution lifetimes.

                      Scope

                      Add Expansion and getExpansion() to @executablemd/core. Introduce @executablemd/workflow with WorkflowRun, useWorkflow({ base }), getWorkflowRun(), and the contextual Git.revParse() capability.

                      getExpansion() replaces the public invocation() metadata reader without an alias. Private invocation lifecycle machinery remains internal.

                      WorkflowRun contains:

                      • runId — an opaque stable identifier;
                      • base — the supplied Git revision; and
                      • pinnedCommit — the commit obtained by resolving the base once.

                      Git.revParse() has the semantics of:

                      git rev-parse --verify --end-of-options <revision>
                      

                      The workflow package depends on @executablemd/core, @executablemd/durable-streams, and @executablemd/runtime. Core never imports workflow or Git.

                      Workflow-run lifetime

                      useWorkflow() installs ordinary middleware in the child scope that owns one document execution. Installing it alone creates no workflow run.

                      The first durable operation:

                      1. allocates a cryptographically random run ID;
                      2. resolves base^{commit} through Git.revParse();
                      3. records one immutable WorkflowRun before root import.

                      getWorkflowRun() is available only inside the associated document execution. It throws:

                      • before execute() starts;
                      • when execute() has no useWorkflow() installation; and
                      • after that document execution completes, even while the installer scope still exists.

                      Concurrent document executions remain isolated through Effection scope ownership.

                      Replay

                      Replay restores the recorded WorkflowRun without allocating another run ID or invoking Git. The supplied base must equal the recorded base. A completed journal must restore workflow metadata before the root-close shortcut, and a malformed record is refused rather than coerced.

                      Expansion identity

                      Expansion reports id, authored name, and opening-tag source position when known. Its ID derives from root document and structural expansion path, never from process-global state, time, randomness, scheduling order, or run ID.

                      Replay, retry attempts, and restoration of the same loop iteration preserve the ID. Distinct authored elements, loop iterations, projections, component expansions, and root documents receive distinct IDs.

                      Acceptance

                      • Every descendant observes one frozen WorkflowRun by reference during a live document execution.
                      • getWorkflowRun() obeys the exact before/during/after lifetime above.
                      • Replay invokes neither run-ID allocation nor Git and refuses a changed base.
                      • Git failures occur before root import and record no successful WorkflowRun.
                      • Ordinary execute() and xmd run remain Git-independent without workflow middleware.
                      • getExpansion() throws outside an executable element expansion and exposes no props, bindings, selected component, projected content, or live scope.
                      • Expansion IDs satisfy every determinism and distinction claim above.
                      • Workflow-wide durable identity combines run ID and expansion ID; the expansion ID does not embed the run ID.
                      • Tests discriminate scope, derivation, replay, and Git-resolution boundaries.

                      Intentionally excluded

                      Dependencies

                      Activity

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

                      Metadata

                      Metadata

                      Assignees

                      No one assigned

                        Labels

                        No labels
                        No labels

                        Projects

                        No projects

                          Relationships

                          None yet

                          Development

                          No branches or pull requests

                          Issue actions

                          , '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

                          Add contextual workflow runs with pinned commits #289

                          Description

                          @taras

                          Story

                          As a workflow author, I want each workflow run tied to one pinned starting commit and each executable element identified deterministically, so durable records and effects have explicit identities without extending execution lifetimes.

                          Scope

                          Add Expansion and getExpansion() to @executablemd/core. Introduce @executablemd/workflow with WorkflowRun, useWorkflow({ base }), getWorkflowRun(), and the contextual Git.revParse() capability.

                          getExpansion() replaces the public invocation() metadata reader without an alias. Private invocation lifecycle machinery remains internal.

                          WorkflowRun contains:

                          • runId — an opaque stable identifier;
                          • base — the supplied Git revision; and
                          • pinnedCommit — the commit obtained by resolving the base once.

                          Git.revParse() has the semantics of:

                          git rev-parse --verify --end-of-options <revision>
                          

                          The workflow package depends on @executablemd/core, @executablemd/durable-streams, and @executablemd/runtime. Core never imports workflow or Git.

                          Workflow-run lifetime

                          useWorkflow() installs ordinary middleware in the child scope that owns one document execution. Installing it alone creates no workflow run.

                          The first durable operation:

                          1. allocates a cryptographically random run ID;
                          2. resolves base^{commit} through Git.revParse();
                          3. records one immutable WorkflowRun before root import.

                          getWorkflowRun() is available only inside the associated document execution. It throws:

                          • before execute() starts;
                          • when execute() has no useWorkflow() installation; and
                          • after that document execution completes, even while the installer scope still exists.

                          Concurrent document executions remain isolated through Effection scope ownership.

                          Replay

                          Replay restores the recorded WorkflowRun without allocating another run ID or invoking Git. The supplied base must equal the recorded base. A completed journal must restore workflow metadata before the root-close shortcut, and a malformed record is refused rather than coerced.

                          Expansion identity

                          Expansion reports id, authored name, and opening-tag source position when known. Its ID derives from root document and structural expansion path, never from process-global state, time, randomness, scheduling order, or run ID.

                          Replay, retry attempts, and restoration of the same loop iteration preserve the ID. Distinct authored elements, loop iterations, projections, component expansions, and root documents receive distinct IDs.

                          Acceptance

                          • Every descendant observes one frozen WorkflowRun by reference during a live document execution.
                          • getWorkflowRun() obeys the exact before/during/after lifetime above.
                          • Replay invokes neither run-ID allocation nor Git and refuses a changed base.
                          • Git failures occur before root import and record no successful WorkflowRun.
                          • Ordinary execute() and xmd run remain Git-independent without workflow middleware.
                          • getExpansion() throws outside an executable element expansion and exposes no props, bindings, selected component, projected content, or live scope.
                          • Expansion IDs satisfy every determinism and distinction claim above.
                          • Workflow-wide durable identity combines run ID and expansion ID; the expansion ID does not embed the run ID.
                          • Tests discriminate scope, derivation, replay, and Git-resolution boundaries.

                          Intentionally excluded

                          Dependencies

                          Activity

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

                          Metadata

                          Metadata

                          Assignees

                          No one assigned

                            Labels

                            No labels
                            No labels

                            Projects

                            No projects

                              Relationships

                              None yet

                              Development

                              No branches or pull requests

                              Issue actions

                              , '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

                              Add contextual workflow runs with pinned commits #289

                              Description

                              @taras

                              Story

                              As a workflow author, I want each workflow run tied to one pinned starting commit and each executable element identified deterministically, so durable records and effects have explicit identities without extending execution lifetimes.

                              Scope

                              Add Expansion and getExpansion() to @executablemd/core. Introduce @executablemd/workflow with WorkflowRun, useWorkflow({ base }), getWorkflowRun(), and the contextual Git.revParse() capability.

                              getExpansion() replaces the public invocation() metadata reader without an alias. Private invocation lifecycle machinery remains internal.

                              WorkflowRun contains:

                              • runId — an opaque stable identifier;
                              • base — the supplied Git revision; and
                              • pinnedCommit — the commit obtained by resolving the base once.

                              Git.revParse() has the semantics of:

                              git rev-parse --verify --end-of-options <revision>
                              

                              The workflow package depends on @executablemd/core, @executablemd/durable-streams, and @executablemd/runtime. Core never imports workflow or Git.

                              Workflow-run lifetime

                              useWorkflow() installs ordinary middleware in the child scope that owns one document execution. Installing it alone creates no workflow run.

                              The first durable operation:

                              1. allocates a cryptographically random run ID;
                              2. resolves base^{commit} through Git.revParse();
                              3. records one immutable WorkflowRun before root import.

                              getWorkflowRun() is available only inside the associated document execution. It throws:

                              • before execute() starts;
                              • when execute() has no useWorkflow() installation; and
                              • after that document execution completes, even while the installer scope still exists.

                              Concurrent document executions remain isolated through Effection scope ownership.

                              Replay

                              Replay restores the recorded WorkflowRun without allocating another run ID or invoking Git. The supplied base must equal the recorded base. A completed journal must restore workflow metadata before the root-close shortcut, and a malformed record is refused rather than coerced.

                              Expansion identity

                              Expansion reports id, authored name, and opening-tag source position when known. Its ID derives from root document and structural expansion path, never from process-global state, time, randomness, scheduling order, or run ID.

                              Replay, retry attempts, and restoration of the same loop iteration preserve the ID. Distinct authored elements, loop iterations, projections, component expansions, and root documents receive distinct IDs.

                              Acceptance

                              • Every descendant observes one frozen WorkflowRun by reference during a live document execution.
                              • getWorkflowRun() obeys the exact before/during/after lifetime above.
                              • Replay invokes neither run-ID allocation nor Git and refuses a changed base.
                              • Git failures occur before root import and record no successful WorkflowRun.
                              • Ordinary execute() and xmd run remain Git-independent without workflow middleware.
                              • getExpansion() throws outside an executable element expansion and exposes no props, bindings, selected component, projected content, or live scope.
                              • Expansion IDs satisfy every determinism and distinction claim above.
                              • Workflow-wide durable identity combines run ID and expansion ID; the expansion ID does not embed the run ID.
                              • Tests discriminate scope, derivation, replay, and Git-resolution boundaries.

                              Intentionally excluded

                              Dependencies

                              Activity

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

                              Metadata

                              Metadata

                              Assignees

                              No one assigned

                                Labels

                                No labels
                                No labels

                                Projects

                                No projects

                                  Relationships

                                  None yet

                                  Development

                                  No branches or pull requests

                                  Issue actions