@bongos/core 1.19.714 → 1.19.724
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.bongos-core.json +488 -413
- package/.claude/skills/backlog-review/SKILL.md +3 -3
- package/.claude/skills/blocker-review/SKILL.md +1 -1
- package/.claude/skills/blocker-solve/SKILL.md +2 -2
- package/.claude/skills/builder-reauth/SKILL.md +1 -1
- package/.claude/skills/builder-redteam/SKILL.md +1 -1
- package/.claude/skills/builder-ship/SKILL.md +1 -1
- package/.claude/skills/builder-start/SKILL.md +1 -1
- package/.claude/skills/design/SKILL.md +2 -2
- package/.claude/skills/feedback/SKILL.md +1 -1
- package/.claude/skills/goal-create/SKILL.md +1 -1
- package/.claude/skills/goal-review/SKILL.md +2 -2
- package/.claude/skills/idea-triage/SKILL.md +5 -5
- package/.claude/skills/merge-mode/SKILL.md +4 -4
- package/.claude/skills/new-project/SKILL.md +17 -17
- package/.claude/skills/planning-session/SKILL.md +11 -11
- package/.claude/skills/recall/SKILL.md +2 -2
- package/.claude/skills/strand-fix/SKILL.md +1 -1
- package/.devcontainer/README.md +2 -2
- package/CONTRIBUTING.md +2 -2
- package/GOVERNANCE.md +4 -4
- package/clients/bongos-client/README.md +1 -1
- package/clients/bongos-client/bongos-client.global.js +4 -0
- package/clients/bongos-client/index.cjs +4 -0
- package/clients/bongos-client/index.d.ts +5 -0
- package/clients/bongos-client/index.mjs +4 -0
- package/config/branding.neutral.json +4 -2
- package/docs/adr/0001-stack-choice-single-vps.md +2 -2
- package/docs/adr/0002-digitalocean-over-hetzner.md +1 -1
- package/docs/adr/0008-google-chat-oauth-user-auth.md +1 -1
- package/docs/adr/0009-autotile-architecture.md +1 -1
- package/docs/adr/0011-terrain-id-rendering-model.md +3 -3
- package/docs/adr/0013-paths-as-object-overlays-with-autotile-dispatch.md +1 -1
- package/docs/adr/0014-families-canonical-over-vocabulary.md +1 -1
- package/docs/adr/0015-task-dependencies-and-auto-promotion.md +1 -1
- package/docs/adr/0016-trust-boundary-server-enforced-permissions.md +1 -1
- package/docs/adr/0018-three-rank-model-goes-live.md +3 -3
- package/docs/adr/0020-security-model-public-stub.md +9 -9
- package/docs/adr/0021-per-builder-skill-model-preferences.md +2 -2
- package/docs/adr/0022-secrets-policy.md +5 -5
- package/docs/adr/0024-cloneable-repo-local-first-memory.md +3 -3
- package/docs/adr/0024-multi-agent-system-architecture.md +10 -10
- package/docs/adr/0025-offsite-backup-vendor-digitalocean-spaces.md +1 -1
- package/docs/adr/0025-structured-criterion-task-link.md +1 -1
- package/docs/adr/0026-bfg-memory-hygiene-and-cross-builder-learning.md +13 -13
- package/docs/adr/0027-bfg-session-inefficiency-evaluator.md +14 -14
- package/docs/adr/0029-status-page-outage-resilience.md +1 -1
- package/docs/adr/0030-builders-hall-live-updates.md +1 -1
- package/docs/adr/0031-cloud-dev-environments-for-builders.md +7 -7
- package/docs/adr/0032-discord-mirror-of-gds.md +3 -3
- package/docs/adr/0033-discord-bot-service-principal.md +4 -4
- package/docs/adr/0034-thetes-graduated-newcomer-rank.md +1 -1
- package/docs/adr/0035-builder-onboarding-three-paths.md +4 -4
- package/docs/adr/0036-builders-subdomain-and-ui-reorg.md +1 -1
- package/docs/adr/0037-discord-channel-management.md +1 -1
- package/docs/adr/0038-chromebook-ttyd-cloudflare-tunnel.md +5 -5
- package/docs/adr/0039-setup-first-onboarding-ux.md +6 -6
- package/docs/adr/0040-remote-control-default-browser-onramp.md +3 -3
- package/docs/adr/0041-temporary-grader-bypass-killswitch.md +2 -2
- package/docs/adr/0042-builder-self-deploy-ci-auto-merge.md +5 -5
- package/docs/adr/0043-git-ssh-trust-boundary-and-rank-floor-on-permission-paths.md +2 -2
- package/docs/adr/0044-mediterranean-palette-replacement.md +1 -1
- package/docs/adr/0044-per-box-live-game-preview.md +1 -1
- package/docs/adr/0046-sandbox-first-review-gate.md +1 -1
- package/docs/adr/0047-discord-bugs-intake-anti-abuse.md +1 -1
- package/docs/adr/0049-split-parallel-safety-contract.md +1 -1
- package/docs/adr/0050-device-flow-admission-invite-gated-by-default.md +2 -2
- package/docs/adr/0051-full-session-transcript-corpus.md +2 -2
- package/docs/adr/0052-sandbox-for-everyone-game-only-preview.md +1 -1
- package/docs/adr/0053-scoped-dev-box-session.md +1 -1
- package/docs/adr/0054-session-token-reward-cost-plus.md +7 -7
- package/docs/adr/0055-server-mediated-branch-publish.md +2 -2
- package/docs/adr/0056-prod-deploy-script-mirror-and-healthcheck-retry.md +3 -3
- package/docs/adr/0057-container-cost-ledger.md +1 -1
- package/docs/adr/0057-discord-archon-approval-channels.md +2 -2
- package/docs/adr/0058-automatic-gate-surface-gatekeeper.md +6 -6
- package/docs/adr/0059-single-approval-remove-devbox-approval-gate.md +11 -11
- package/docs/adr/0060-gds-retrieval-layer.md +3 -3
- package/docs/adr/0061-context-layer-decomposition.md +2 -2
- package/docs/adr/0062-medusa-instance-model-decoupling.md +5 -5
- package/docs/adr/0063-generated-repo-map-symbol-skeleton.md +2 -2
- package/docs/adr/0064-rename-medusa-to-cloud-bongos.md +3 -3
- package/docs/adr/0065-agpl-nonprofit-ai-first-governance.md +5 -5
- package/docs/adr/0066-generated-file-map-sections.md +2 -2
- package/docs/adr/0067-session-start-fast-forward-pull.md +1 -1
- package/docs/adr/0068-shared-art-key-for-newcomers.md +1 -1
- package/docs/adr/0069-hall-live-channel-sse-decouple.md +3 -3
- package/docs/adr/0070-deterministic-session-card-delivery.md +1 -1
- package/docs/adr/0071-box-confirm-before-destroyed-and-drift-reconcile.md +2 -2
- package/docs/adr/0072-bongos-app-mac-signed-first-windows-deferred.md +2 -2
- package/docs/adr/0072-dev-box-code-staleness-visibility.md +2 -2
- package/docs/adr/0073-builder-needs-signal-and-byok-gemini-key.md +3 -3
- package/docs/adr/0073-secrets-scan-exclude-uri-detector.md +2 -2
- package/docs/adr/0076-in-session-deterministic-compaction.md +2 -2
- package/docs/adr/0077-content-addressed-llm-cache.md +2 -2
- package/docs/adr/0078-deterministic-first-cron.md +3 -3
- package/docs/adr/0079-value-gated-autonomous-engagement.md +2 -2
- package/docs/adr/0080-llm-cache-api-transport-and-trust-model.md +3 -3
- package/docs/adr/0081-tool-agnostic-design-layer.md +3 -3
- package/docs/adr/0082-server-side-merge-conflict-auto-resolution.md +2 -2
- package/docs/adr/0083-modular-architecture-strangler-build-plan.md +3 -3
- package/docs/adr/0085-remove-default-per-builder-spend-cap.md +2 -2
- package/docs/adr/0086-goal-scoped-work-hierarchy.md +15 -15
- package/docs/adr/0087-bongos-app-architecture-and-handoff-contract.md +5 -5
- package/docs/adr/0087-compete-on-governance-not-tooling-cursor.md +1 -1
- package/docs/adr/0088-consistent-character-generative-animation.md +5 -5
- package/docs/adr/0089-modular-multi-model-adversarial-grader.md +15 -15
- package/docs/adr/0090-metic-task-authoring.md +8 -8
- package/docs/adr/0091-bounding-the-kernel-and-db-carve.md +3 -3
- package/docs/adr/0092-hosting-module-and-on-prem-target.md +11 -11
- package/docs/adr/0093-tranche-2-core-carve-sequence.md +5 -5
- package/docs/adr/0094-repo-atlas-self-drawing-codebase-map.md +1 -1
- package/docs/adr/0095-borrowed-memory-and-retrieval-concepts.md +6 -6
- package/docs/adr/0095-cross-agent-context-management.md +5 -5
- package/docs/adr/0096-require-reward-before-workable.md +5 -5
- package/docs/adr/0097-one-active-claim-per-session-and-worktree-binding.md +2 -2
- package/docs/adr/0097-retroactive-reward-backfill.md +4 -4
- package/docs/adr/0098-public-mirror-publish-manifest.md +3 -3
- package/docs/adr/0099-delayed-redacted-mirror-export.md +1 -1
- package/docs/adr/0100-two-repo-instance-model.md +6 -6
- package/docs/adr/0101-goal-hierarchy-phase-5-judge-membership-reward.md +9 -9
- package/docs/adr/0102-finish-bounding-the-kernel.md +1 -1
- package/docs/adr/0103-core-first-extraction-cloud-bongos-trunk.md +6 -6
- package/docs/adr/0103-gdsv4-bongos-consolidation.md +3 -3
- package/docs/adr/0104-trust-gds-api-channel-in-auto-mode.md +3 -3
- package/docs/adr/0105-instance-seed-migrations-out-of-core.md +2 -2
- package/docs/adr/0106-goal-owner-manager-authority.md +2 -2
- package/docs/adr/0107-module-upstreaming-contribution-to-core-catalog.md +6 -6
- package/docs/adr/0108-instance-composition-configurable-root.md +6 -6
- package/docs/adr/0109-self-describing-openapi-and-hosted-docs.md +3 -3
- package/docs/adr/0110-untrack-whole-file-generated-nav-docs.md +1 -1
- package/docs/adr/0111-instance-hosting-provisioning-module.md +18 -18
- package/docs/adr/0112-private-goals-invitations-join-requests.md +7 -7
- package/docs/adr/0113-sandbox-studio-descope-superseded-by-0044-0052.md +1 -1
- package/docs/adr/0114-instance-docs-discovery-contract.md +4 -4
- package/docs/adr/0115-scheduled-routines-portability.md +1 -1
- package/docs/adr/0117-api-versioning-and-deprecation-policy.md +1 -1
- package/docs/adr/0118-api-contract-source-of-truth-code-first.md +1 -1
- package/docs/adr/0120-pay-on-land-and-builder-owned-rebase-gate.md +2 -2
- package/docs/adr/0121-greenfield-vs-brownfield-onboarding-adopt-existing-repo.md +1 -1
- package/docs/adr/0122-onboarding-diagram-renders-deploy-rendered-off-git.md +3 -3
- package/docs/adr/0123-box-idle-sweep-autosave-before-destroy.md +1 -1
- package/docs/adr/0124-typed-api-response-bodies.md +2 -2
- package/docs/adr/0125-control-plane-scaffolds-standalone-instance-repo.md +2 -2
- package/docs/adr/0126-dedicated-cloudbongos-control-plane-droplet.md +3 -3
- package/docs/adr/0127-cross-box-fleet-observability.md +1 -1
- package/docs/adr/0128-provisioning-runner-privilege-and-db-auth-model.md +3 -3
- package/docs/adr/0129-cloudbongos-control-plane-pull-deploy.md +4 -4
- package/docs/adr/0130-provision-remote-exec-over-ssh.md +4 -4
- package/docs/adr/0131-rank-scoped-skill-visibility.md +2 -2
- package/docs/adr/0132-cohost-fleet-control-plane-migration.md +2 -2
- package/docs/adr/0133-github-app-manifest-onboarding-signin.md +1 -1
- package/docs/adr/0134-private-first-npm-distribution.md +3 -3
- package/docs/adr/0135-module-upstream-submission-interim-queue.md +1 -1
- package/docs/adr/0136-update-channel-subscription-policy.md +2 -2
- package/docs/adr/0137-upstream-publish-policy-manual-owner-gated.md +6 -6
- package/docs/adr/0138-bundled-module-deps-declared-per-module.md +4 -4
- package/docs/adr/0142-project-context-is-prose-only.md +2 -2
- package/docs/adr/0143-onboarding-repo-picker-oauth-scope.md +2 -2
- package/docs/adr/0144-devbox-rehome-onto-cloudbongos-plane.md +2 -2
- package/docs/adr/0145-free-hosted-project-tier-isolation-and-domain-separation.md +2 -2
- package/docs/adr/0146-configurable-reward-mode-cost-plus-only.md +4 -4
- package/docs/adr/0147-standalone-live-docs-regen.md +1 -1
- package/docs/adr/0149-bongos-dev-local-launcher.md +1 -1
- package/docs/adr/0150-box-first-boot-bringup-vendored-instances.md +3 -3
- package/docs/adr/0151-governance-permissions-as-atom-ranks-as-roles.md +20 -20
- package/docs/adr/0152-landing-gate-served-by-the-core-app.md +2 -2
- package/docs/adr/0152-metic-task-abandonment.md +7 -7
- package/docs/adr/0153-sequential-chain-runner.md +1 -1
- package/docs/adr/0154-goal-owner-criterion-authoring.md +7 -7
- package/docs/adr/0155-adopt-private-repo-widen-oauth-scope.md +2 -2
- package/docs/adr/0156-user-set-display-name-wins.md +1 -1
- package/docs/adr/0157-archon-is-rank-and-identity-only.md +10 -10
- package/docs/adr/0158-choke-point-verdict-taxonomy.md +1 -1
- package/docs/adr/0159-merge-gate-reconciliation.md +1 -1
- package/docs/adr/0160-main-audit-repo-verifiable-caller.md +1 -1
- package/docs/adr/0161-publish-on-merge.md +2 -2
- package/docs/adr/0163-legacy-display-name-resolution.md +1 -1
- package/docs/adr/0165-instances-hookless-by-default.md +1 -1
- package/docs/adr/0166-module-maintenance-and-deprecation-policy.md +3 -3
- package/docs/adr/0167-gate-trust-link-agpl-default.md +2 -2
- package/docs/adr/0167-module-catalog-source-vs-provenance.md +3 -3
- package/docs/adr/0169-bongos-serve-server-bring-up.md +1 -1
- package/docs/adr/0171-profile-rollup-join-and-consent.md +1 -1
- package/docs/adr/0172-editable-rank-roles-substrate-axis.md +2 -2
- package/docs/adr/0172-per-craft-compensation-ideator-credit-lane.md +4 -4
- package/docs/adr/0173-legacy-multi-ship-shortfall-not-backfilled.md +1 -1
- package/docs/adr/0174-government-terminology-ranks-not-roles.md +1 -1
- package/docs/adr/0177-goal-membership-kind.md +3 -3
- package/docs/adr/0178-the-copy-desk-flag-and-queue.md +1 -1
- package/docs/adr/0179-board-membership-predicate-grammar.md +1 -1
- package/docs/adr/0181-teardown-state-gate-and-address-retention.md +1 -1
- package/docs/adr/0182-project-visibility-two-axes.md +1 -1
- package/docs/adr/0183-criteria-close-themselves.md +1 -1
- package/docs/adr/0184-ship-requires-an-assurance.md +1 -1
- package/docs/adr/0185-spark-handoff-credit-split.md +1 -1
- package/docs/adr/0186-per-project-idea-templates.md +1 -1
- package/docs/adr/0187-collab-four-decisions.md +1 -1
- package/docs/adr/0187-oauth-handshake-cookie-lifetime.md +1 -1
- package/docs/adr/0188-patrol-runs-on-ci-not-the-server.md +2 -2
- package/docs/adr/0189-baseline-floors-and-the-freeze-detector.md +2 -2
- package/docs/adr/0191-majority-and-the-author-who-may-not-decide-alone.md +1 -1
- package/docs/adr/0192-a-category-orients-and-authorises-nothing.md +2 -2
- package/docs/adr/0193-pause-task-scoped-box-slices.md +1 -1
- package/docs/adr/0195-adr-numbers-are-checked-like-migration-numbers.md +2 -2
- package/docs/adr/0196-chrome-world-token-contract-and-the-landing-sheets.md +2 -2
- package/docs/adr/0197-the-ui-design-module.md +1 -1
- package/docs/adr/0198-third-party-skill-vendoring-policy.md +1 -1
- package/docs/adr/0203-doorway-changelog-out-of-module-api.md +2 -2
- package/docs/adr/0204-the-apex-is-dark-only.md +2 -2
- package/docs/adr/0205-federated-checkin-needs-the-hubs-own-signin-witness.md +1 -1
- package/docs/adr/0206-own-scoped-session-revocation-no-absolute-ceiling.md +1 -1
- package/docs/adr/0207-connections-implementation-departures-and-honest-limits.md +1 -1
- package/docs/adr/0208-application-lifecycle-the-handle-waits-and-the-vouch-has-no-minter.md +2 -2
- package/docs/adr/0209-one-budget-for-the-account-existence-oracle.md +1 -1
- package/docs/adr/0210-scouting-graduates-on-an-instance-asserted-owner-claim.md +1 -1
- package/docs/adr/0212-connections-on-the-profile-surface-and-addressing.md +1 -1
- package/docs/adr/0213-platform-terms-acceptance-is-the-hubs-own-witness.md +2 -2
- package/docs/adr/0215-the-recruiter-sliver-is-a-ceiling-not-a-step.md +6 -6
- package/docs/adr/0216-a-fake-pool-interpreter-must-fail-loudly-not-silently-ignore.md +2 -2
- package/docs/adr/0217-rank-gates-inviting-not-viewing.md +1 -1
- package/docs/adr/0218-the-apex-root-web-surface.md +2 -2
- package/docs/adr/0219-a-look-is-a-branding-pack-the-style-library.md +1 -1
- package/docs/adr/0220-an-in-house-rebuilt-skill-is-a-first-party-skill.md +1 -1
- package/docs/adr/0221-the-impeccable-method-is-one-skill-with-sub-command-playbooks.md +2 -2
- package/docs/adr/0222-the-image-family-under-the-hero-only-rule.md +2 -2
- package/docs/adr/0223-the-detector-is-two-tiers-in-the-kit.md +3 -3
- package/docs/adr/0224-module-skills-reach-the-core-checkout-as-untracked-self-ignored-copies.md +1 -1
- package/docs/adr/0225-privacy-suppresses-cross-project-surfaces-only.md +1 -1
- package/docs/adr/0226-one-stale-timer-reporting-degrades-enforcement-refuses.md +1 -1
- package/docs/adr/0227-a-task-network-map-is-refused-the-goal-graph-is-the-map.md +1 -1
- package/docs/adr/0230-a-look-skill-is-a-composition-grammar-the-palette-is-the-pack.md +1 -1
- package/docs/adr/0231-the-style-session-an-owner-authors-a-look-inside-the-contract.md +2 -2
- package/docs/adr/0232-rot-is-derived-not-swept-and-water-is-the-only-new-verb.md +2 -2
- package/docs/adr/0233-a-copy-proposal-is-a-task-carrying-a-patch.md +2 -2
- package/docs/adr/0234-idea-routing-capture-time-promotion-landing-matrix-homeless-inbox.md +2 -2
- package/docs/adr/0235-a-fix-category-is-kindbug-under-a-goal-no-column-required.md +11 -11
- package/docs/adr/0236-many-ideas-one-task-the-lineage-key-is-the-pair.md +5 -5
- package/docs/adr/0237-a-starter-bundle-is-a-preset-over-the-always-on-core-keyed-by-declared-type.md +5 -5
- package/docs/adr/0238-the-join-door-is-a-provisioning-settings-policy-key.md +1 -1
- package/docs/adr/0239-a-recommendation-is-a-table-that-carries-its-own-reason.md +4 -4
- package/docs/adr/0240-a-skipped-module-picker-stores-nothing-and-resolves-the-bundle-on-read.md +4 -4
- package/docs/adr/0241-the-artist-gate-is-a-per-project-deploy-gate-that-reads-a-state.md +1 -1
- package/docs/adr/0242-a-cascade-is-a-declaration-table-on-the-event-that-already-exists.md +2 -2
- package/docs/adr/0243-a-bundle-adjustment-belongs-to-the-bundle-not-the-advice-about-it.md +4 -4
- package/docs/adr/0244-a-catalog-search-is-a-view-over-the-rows-never-an-edit-to-the-selection.md +3 -3
- package/docs/adr/0245-the-way-back-into-an-optional-step-is-that-step-s-own-answer-route.md +7 -7
- package/docs/adr/0246-catalog-membership-is-a-projection-not-a-federation-side-effect.md +1 -1
- package/docs/adr/0247-the-join-door-is-one-composed-answer-and-dark-matter-has-no-live-verdict-yet.md +2 -2
- package/docs/adr/0248-a-hub-project-s-owner-is-the-provisioning-row-carried-on-a-port.md +3 -3
- package/docs/adr/0249-the-invite-step-is-the-done-panel-s-first-act-not-a-rail-step.md +3 -3
- package/docs/adr/0250-strict-versioning-the-version-boundary-is-the-scope-gate.md +6 -6
- package/docs/adr/0251-a-suggestion-of-who-to-invite-is-a-recruiting-surface-and-owes-the-opt-out.md +5 -5
- package/docs/adr/0252-the-self-hosted-visibility-report-is-a-pull-and-auto-appear-buys-a-retraction-lever.md +19 -19
- package/docs/adr/0253-the-takedown-lever-has-two-writers-and-provenance-is-a-column.md +2 -2
- package/docs/adr/0254-a-relayed-link-is-contained-downward-or-it-is-not-published.md +6 -6
- package/docs/adr/0255-a-public-lists-ordering-is-part-of-its-payload.md +2 -2
- package/docs/adr/0256-the-visibility-ceiling-is-the-sign-in-gate-too-and-the-reader-moves-to-the-composer.md +3 -3
- package/docs/adr/0257-auth-resolves-before-the-hall-mounts-anything.md +1 -1
- package/docs/adr/0258-the-public-cli-is-a-generated-client-package-not-the-published-core.md +1 -1
- package/docs/adr/0259-a-projects-departure-from-the-public-list-is-public.md +7 -7
- package/docs/adr/0260-the-application-is-the-consent-and-the-echo-is-the-gate.md +4 -4
- package/docs/adr/0261-a-preselect-always-carries-a-reason-the-bundle-summary-is-the-floor.md +1 -1
- package/docs/adr/0262-a-bug-never-lands-in-the-inbox.md +1 -1
- package/docs/adr/0263-how-a-version-closes.md +3 -3
- package/docs/adr/0264-the-ten-working-areas.md +3 -3
- package/docs/adr/0265-work-with-no-goal-and-the-order-the-cut-needs.md +5 -5
- package/docs/adr/0266-the-board-room-is-its-own-surface-reachable-by-whoever-may-vote.md +2 -2
- package/docs/adr/0267-unanimity-and-the-revise-and-re-sit-loop.md +1 -1
- package/docs/adr/0268-the-constitution-comes-from-two-roots.md +3 -3
- package/docs/adr/0269-the-cli-session-store-is-host-keyed-at-a-fixed-anchor.md +1 -1
- package/docs/adr/0270-rank-floor-derives-without-a-prediction.md +2 -2
- package/docs/adr/0271-the-ideator-surface-is-two-halves.md +3 -3
- package/docs/adr/0272-a-craft-is-an-identity-not-a-toolchain.md +4 -4
- package/docs/adr/0273-hall-nav-can-gate-on-a-permission.md +1 -1
- package/docs/adr/0274-one-kernel-three-role-packs.md +1 -1
- package/docs/adr/0275-one-source-for-a-written-role-responsibility.md +1 -1
- package/docs/adr/0276-the-skill-listing-budget-cannot-hold-every-trigger.md +1 -1
- package/docs/adr/0277-a-box-is-in-use-only-while-a-human-is-attached.md +1 -1
- package/docs/adr/0278-a-gated-project-still-takes-applications.md +2 -2
- package/docs/adr/0279-an-upgrade-is-proven-by-the-served-version-not-the-health-check.md +1 -1
- package/docs/adr/0280-the-unattended-lane-may-drive-a-co-tenant-because-the-roster-is-the-decision.md +1 -1
- package/docs/adr/0281-an-instance-identity-is-its-own-unix-account-and-pg-role.md +2 -2
- package/docs/adr/README.md +294 -294
- package/docs/api/openapi.json +72 -5
- package/docs/api-reference.md +8 -2
- package/docs/architecture.md +22 -22
- package/docs/branding-contract.md +5 -5
- package/docs/canonical-permissions.md +22 -22
- package/docs/copy-inventory.md +15 -13
- package/docs/copy-registry.json +35 -17
- package/docs/design/hall-direction-v2.md +3 -3
- package/docs/design/landing-page-direction-v2.md +1 -1
- package/docs/design/projects-hub-direction-v2.md +1 -1
- package/docs/file-map.md +3 -1
- package/docs/module-api-changelog.md +36 -1
- package/docs/modules-contract.md +25 -25
- package/docs/onboarding/browser-terminal-guide.md +1 -1
- package/docs/onboarding/diagrams/README.md +3 -3
- package/docs/onboarding/drachmae-and-karma.md +13 -13
- package/docs/onboarding/primer.md +7 -7
- package/docs/packs/artist.md +1 -1
- package/docs/packs/ideator.md +1 -1
- package/docs/project-context.template.md +3 -3
- package/docs/recipes/builder-box-lifecycle.md +5 -5
- package/docs/recipes/claude-design-loop.md +1 -1
- package/docs/recipes/core-release-pipeline.md +55 -14
- package/docs/recipes/figma-design-loop.md +1 -1
- package/docs/recipes/gds-db-backup.md +2 -2
- package/docs/recipes/instance-deploy.md +2 -2
- package/docs/recipes/instance-service-restart.md +3 -3
- package/docs/recipes/local-dev.md +2 -2
- package/docs/recipes/managed-settings-remote-control.md +3 -3
- package/docs/recipes/memory-backup.md +4 -4
- package/docs/recipes/memory-sync-conflicts.md +2 -2
- package/docs/recipes/multi-builder-merge.md +2 -2
- package/docs/recipes/ops-gotchas.md +4 -4
- package/docs/recipes/overnight-builder.md +1 -1
- package/docs/recipes/packaging-the-core.md +6 -6
- package/docs/recipes/private-npm-distribution.md +5 -5
- package/docs/recipes/search-index-ingestion.md +3 -3
- package/docs/recipes/self-host.md +5 -5
- package/docs/recipes/server-bring-up.md +1 -1
- package/docs/recipes/ship-and-regrade.md +2 -2
- package/docs/recipes/standalone-live-docs.md +1 -1
- package/docs/recipes/ui-look-before-you-ship.md +1 -1
- package/docs/recipes/upgrading-the-core.md +2 -2
- package/docs/recipes/work-on-a-task-from-your-dev-box.md +6 -6
- package/docs/research/cursor-competitive-analysis.md +3 -3
- package/docs/research/llm-model-agnostic-and-cheaper-grader.md +7 -7
- package/migrations/core_240_artist_gate_indexes.sql +48 -0
- package/migrations/core_240_goal_members_drop_legacy_role.sql +79 -0
- package/modules/dev-box/app/src/vendor/bongos-client.cjs +4 -0
- package/modules/hall-ui/public/watch.css +6 -0
- package/modules/hall-ui/public/watch.js +52 -6
- package/modules/lifecycle/cascade.js +37 -9
- package/modules/lifecycle/db-claims.js +5 -2
- package/modules/lifecycle/db-goals.js +4 -3
- package/modules/lifecycle/db-overrides.js +117 -4
- package/modules/lifecycle/db-tasks.js +63 -0
- package/modules/lifecycle/migrations/lifecycle_001_goal_first_leads.sql +12 -4
- package/modules/lifecycle/module.json +2 -1
- package/modules/lifecycle/pg-constraint-fail.js +49 -0
- package/modules/lifecycle/routes/artist-gate.js +101 -0
- package/modules/lifecycle/routes/claims.js +13 -1
- package/modules/lifecycle/routes/lifecycle.js +6 -0
- package/modules/lifecycle/routes/task-write-routes.js +7 -0
- package/modules/lifecycle/routes/tasks.js +24 -0
- package/modules/lifecycle/task-classifier.js +10 -1
- package/modules/lifecycle/tests/cascade.mjs +43 -0
- package/modules/provisioning/provisioning.js +79 -3
- package/modules/provisioning/routes/provisioning.js +6 -1
- package/modules/provisioning/tests/provisioning.mjs +8 -8
- package/modules/security/secret-scrub.js +40 -4
- package/modules/status-ui/public/README.md +1 -1
- package/modules/ui-design/docs/design-contract.md +2 -2
- package/modules/ui-design/kit/README.md +1 -1
- package/modules/ui-design/kit/serve.js +1 -0
- package/modules/ui-design/skills/README.md +6 -6
- package/modules/ui-design/skills/brandkit/SKILL.md +1 -1
- package/modules/ui-design/skills/design-taste-frontend/SKILL.md +1 -1
- package/modules/ui-design/skills/design-taste-frontend-v1/SKILL.md +1 -1
- package/modules/ui-design/skills/gpt-taste/SKILL.md +1 -1
- package/modules/ui-design/skills/high-end-visual-design/SKILL.md +1 -1
- package/modules/ui-design/skills/image-to-code/SKILL.md +1 -1
- package/modules/ui-design/skills/imagegen-frontend-mobile/SKILL.md +1 -1
- package/modules/ui-design/skills/imagegen-frontend-web/SKILL.md +1 -1
- package/modules/ui-design/skills/impeccable/SKILL.md +1 -1
- package/modules/ui-design/skills/industrial-brutalist-ui/SKILL.md +1 -1
- package/modules/ui-design/skills/minimalist-ui/SKILL.md +1 -1
- package/modules/ui-design/skills/redesign-existing-projects/SKILL.md +1 -1
- package/modules/ui-design/skills/stitch-design-taste/SKILL.md +1 -1
- package/modules/ui-design/skills/style/SKILL.md +2 -2
- package/modules/ui-design/styles/README.md +3 -3
- package/modules/ui-design/styles/blueprint/DESIGN.md +1 -1
- package/modules/ui-design/styles/chrome-world/DESIGN.md +1 -1
- package/package-lock.json +2 -2
- package/package.json +1 -1
- package/scripts/gds/audit-rank-roles.js +172 -0
- package/scripts/gds/backfill-task-rewards.js +9 -4
- package/scripts/gds/build-cli-package.js +1 -0
- package/scripts/gds/claim.js +94 -9
- package/scripts/gds/fitness.js +8 -8
- package/scripts/gds/go-live.js +139 -5
- package/scripts/gds/land-watch.js +13 -5
- package/scripts/gds/mirror-redact.js +13 -2
- package/scripts/gds/package-core.js +11 -3
- package/scripts/gds/release.js +55 -0
- package/scripts/gds/ship-land.js +10 -2
- package/scripts/gds/ship-regen.js +41 -8
- package/scripts/gds/start.js +7 -4
- package/scripts/gds/worktree-claim-guard.js +27 -1
- package/scripts/public-mirror-export.js +17 -4
- package/src/bongos/api-errors.js +9 -0
- package/src/bongos/artist-gate.js +204 -0
- package/src/branding.js +15 -0
- package/src/module-api.js +34 -1
- package/tests/api_path_404.mjs +28 -0
- package/tests/artist_gate.mjs +234 -0
- package/tests/artist_gate_release.mjs +283 -0
- package/tests/artist_gate_route.mjs +174 -0
- package/tests/box_scope_predicate.mjs +117 -0
- package/tests/claim_error_surface.mjs +163 -1
- package/tests/cli_exit_no_abort.mjs +256 -3
- package/tests/credit_log_single_writer.mjs +94 -0
- package/tests/currency_label.mjs +11 -4
- package/tests/go_live.mjs +144 -0
- package/tests/helpers.mjs +8 -0
- package/tests/main_worktree_busy_reason.mjs +167 -0
- package/tests/membership_kind_lockstep.mjs +88 -0
- package/tests/mirror_redact.mjs +14 -0
- package/tests/module_api.mjs +6 -0
- package/tests/provision_settings_apply.mjs +13 -5
- package/tests/provisioning_settings.mjs +11 -7
- package/tests/provisioning_settings_apply.mjs +4 -4
- package/tests/provisioning_settings_env.mjs +59 -7
- package/tests/public_mirror_export.mjs +12 -0
- package/tests/rank_roles_audit.mjs +114 -0
- package/tests/scrubber_corpus.mjs +70 -2
- package/tests/start_rebase_warning.mjs +50 -0
- package/tests/task_field_bounds_match_db.mjs +140 -0
- package/tests/watch_roster_self_row.mjs +289 -0
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
- **Status:** Accepted
|
|
4
4
|
- **Date:** 2026-07-08
|
|
5
5
|
- **Task:** [#1770](https://example.com/builders#/task/1770) (BONGOS-V1) — `bongos module submit` + `POST /modules/:key/submit`.
|
|
6
|
-
- **Builds on:** [ADR 0107](
|
|
6
|
+
- **Builds on:** [ADR 0107](0107-module-upstreaming-contribution-to-core-catalog.md) (the upstreaming decision — submit → review → accept), [ADR 0103](0103-core-first-extraction-cloud-bongos-trunk.md) (the core extracted to `github.com/example-owner/cloud-bongos`, private), [ADR 0100](0100-two-repo-instance-model.md) §3 (per-repo GDS — each project runs its own DB).
|
|
7
7
|
|
|
8
8
|
## Context
|
|
9
9
|
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
**Date:** 2026-07-10
|
|
4
4
|
**Status:** Accepted.
|
|
5
|
-
**Context:** [task 2150](https://example.com/builders#/task/2150) (BONGOS-V1, goal 26). The last piece of the update-consumption workstream: [ADR 0100](
|
|
5
|
+
**Context:** [task 2150](https://example.com/builders#/task/2150) (BONGOS-V1, goal 26). The last piece of the update-consumption workstream: [ADR 0100](0100-two-repo-instance-model.md) §2 / [task 1690](https://example.com/builders#/task/1690) gave a consumer the manual `bongos upgrade` channel; [ADR 0134](0134-private-first-npm-distribution.md) / [task 2090](https://example.com/builders#/task/2090) added the private-registry source; [task 2149](https://example.com/builders#/task/2149) added auto-rollback; [task 2157](https://example.com/builders#/task/2157) proved rollback live on the demo instance. What was missing is the **subscription** — how a consumer instance takes new releases *on a cadence, unattended*, rather than a human running `bongos upgrade` each time. Builds on the scheduled-routines portability contract ([ADR 0115](0115-scheduled-routines-portability.md)).
|
|
6
6
|
|
|
7
7
|
## Problem
|
|
8
8
|
|
|
@@ -30,7 +30,7 @@ A **major** bump is never automatic under any channel — a breaking change want
|
|
|
30
30
|
- **Opt-in** — the roster [`config/update-subscriptions.json`](../../config/update-subscriptions.json) ships **empty**; an instance is touched only after an operator lists it (with its dir, systemd unit, health URL, channel, and an optional `env` map so `migrate` hits the right DB).
|
|
31
31
|
- **Health-gated** — per (3).
|
|
32
32
|
|
|
33
|
-
The routine is `mode: deterministic` (System 4, [ADR 0078](
|
|
33
|
+
The routine is `mode: deterministic` (System 4, [ADR 0078](0078-deterministic-first-cron.md)) — it runs as plain `node` with no model session — and **instance-wide** (ADR 0115): one run per instance iterating the roster, not one cron per instance-being-watched.
|
|
34
34
|
|
|
35
35
|
**5. Upstream auto-publish is explicitly split out, not decided here.** For a subscription to deliver anything, new patches must be *published*. Today that is a gated owner step (`package-core.js --publish --live`, ADR 0134). This ADR deliberately scopes the subscription to **consume whatever the owner has published** and does **not** decide whether merges to `main` auto-publish a patch. That is its own decision (publishing cadence, provenance, who holds the token) and is filed as [task 2158](https://example.com/builders#/task/2158). Splitting it lets goal 26 close on the consumption half, which is what the switchover needs.
|
|
36
36
|
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
# 0137 — Upstream publish policy: `@bongos/core` patches are published manually (owner-gated), not auto-published on merge
|
|
2
2
|
|
|
3
|
-
- **Status:** Superseded by [ADR 0161](
|
|
3
|
+
- **Status:** Superseded by [ADR 0161](0161-publish-on-merge.md) (2026-08-08) — after two measured stale-production incidents (171 commits/10 days, 104 commits/5 days), the owner chose publish-on-merge; the "When to revisit" clause below fired.
|
|
4
4
|
- **Date:** 2026-07-10
|
|
5
5
|
- **Deciders:** example-owner (owner/Archon), Claude. Presented the manual-vs-auto fork; the owner chose to keep publishing a manual, owner-triggered step.
|
|
6
|
-
- **Task:** [#2158](https://example.com/builders#/task/2158) (BONGOS-V1, goal 26) — the **supply** half split out of [ADR 0136](
|
|
7
|
-
- **Builds on:** [ADR 0134](
|
|
6
|
+
- **Task:** [#2158](https://example.com/builders#/task/2158) (BONGOS-V1, goal 26) — the **supply** half split out of [ADR 0136](0136-update-channel-subscription-policy.md) §5 / [#2150](https://example.com/builders#/task/2150).
|
|
7
|
+
- **Builds on:** [ADR 0134](0134-private-first-npm-distribution.md) (private-first npm, tokenless tooling), [ADR 0136](0136-update-channel-subscription-policy.md) (subscription consumption policy). **Relates to:** the deferred managed-fleet-control-plane epic ([#1948](https://example.com/builders#/task/1948)).
|
|
8
8
|
|
|
9
9
|
## Context
|
|
10
10
|
|
|
11
|
-
[ADR 0136](
|
|
11
|
+
[ADR 0136](0136-update-channel-subscription-policy.md) (task 2150) built the **consumption** half of the `@bongos/core` update subscription — the channel math (`pinned`/`patch`/`minor`, never `major`/prerelease unattended) and the auto-upgrade routine that consumes published releases on a cadence. It explicitly deferred (§5) the **supply** half: *"does not decide whether merges to `main` auto-publish a patch. That is its own decision (publishing cadence, provenance, who holds the token)."* This ADR is that decision.
|
|
12
12
|
|
|
13
|
-
Today, per [ADR 0134](
|
|
13
|
+
Today, per [ADR 0134](0134-private-first-npm-distribution.md), publishing is a **gated owner step**: `node scripts/gds/package-core.js --publish --live` requires the owner's `npm login` + 2FA, and *the repo/tooling holds no token* ("npm owns auth — this repo never stores a token"). Consumers install with a **read-only** token via an env-fed `.npmrc`. For a subscription to deliver anything, new patches must be published — so the open question was whether to **automate** that publish (on-merge, using a CI-stored write token) or keep it **manual**.
|
|
14
14
|
|
|
15
15
|
## Decision
|
|
16
16
|
|
|
@@ -20,7 +20,7 @@ Today, per [ADR 0134](<redacted>.md), publishing is a **gated owner step**: `nod
|
|
|
20
20
|
2. **Version-bump provenance — deliberate, in-task.** `CORE_VERSION` (`src/module-api.js`) is bumped by hand as part of a task, with a changelog line in the same file (the existing discipline — e.g. task 2148 bumped `1.17.1 → 1.17.2` with a changelog entry). It is **not** auto-bumped. A release publishes whatever `CORE_VERSION` currently is; a stale (un-bumped) version collides with the already-published npm version and npm rejects the duplicate — a natural guard against an accidental no-op republish.
|
|
21
21
|
3. **Token custody — no write-token at rest.** No npm **write** token is stored in CI or the repo. The owner authenticates at publish time (a Classic Automation token bypasses the interactive 2FA-OTP prompt when scripting locally; interactive `npm login` + 2FA otherwise). This preserves ADR 0134's tokenless-tooling posture. Only the **read** token (for consumer / CI installs, env-fed `NPM_TOKEN`) exists.
|
|
22
22
|
4. **No-leak / mirror-redact gate — already fail-closed.** `package-core.js` builds the artifact *through* the no-leak gate (docs genericized + secret-scrubbed; functional files scanned for a live-credential leak) and **produces nothing** if anything leaks, so `--publish` structurally cannot upload a leaking artifact. No extra gate is needed for the manual path — and any future automated path inherits the same fail-closed gate because it runs the same build.
|
|
23
|
-
5. **The subscription is unchanged.** The [ADR 0136](
|
|
23
|
+
5. **The subscription is unchanged.** The [ADR 0136](0136-update-channel-subscription-policy.md) routine consumes whatever the owner has published. Its freshness is bounded by the owner's release cadence — intended and acceptable at current scale.
|
|
24
24
|
|
|
25
25
|
## Why manual over auto (the trade-off)
|
|
26
26
|
|
|
@@ -4,11 +4,11 @@
|
|
|
4
4
|
- **Date:** 2026-07-10
|
|
5
5
|
- **Deciders:** example-owner (owner/Archon), Claude. Presented the fork (keep core lean + declare per-module vs. hoist the dep into `@bongos/core`); the owner chose to keep core lean.
|
|
6
6
|
- **Task:** [#2160](https://example.com/builders#/task/2160) (BONGOS-V1, goal 26) — rehearsal finding **F2** from the R89 cutover rehearsal ([`docs/reviews/<redacted>.md`](../reviews/<redacted>.md)).
|
|
7
|
-
- **Builds on:** [ADR 0108](
|
|
7
|
+
- **Builds on:** [ADR 0108](0108-instance-composition-configurable-root.md) (core consumed as a pinned npm dep; core deps = express+pg), [ADR 0083](0083-modular-architecture-strangler-build-plan.md) (the module manifest contract).
|
|
8
8
|
|
|
9
9
|
## Context
|
|
10
10
|
|
|
11
|
-
The R89 cutover rehearsal converted the example monolith into a `@bongos/core` consumer and surfaced **F2**: with `dependencies: { "@bongos/core" }` alone the consumer boots and then crashes on `Cannot find module 'colyseus'` — and, more subtly, on `Cannot find module 'discord.js'`. The game/art deps (`colyseus`, `phaser`, `sharp`) are obviously the host's. But `discord.js` is different: the **discord module ships INSIDE `@bongos/core`** (it's one of the ~15 bundled core modules), yet `package-core.js` synthesizes only `express` + `pg` as the core's `dependencies` ([ADR 0108](
|
|
11
|
+
The R89 cutover rehearsal converted the example monolith into a `@bongos/core` consumer and surfaced **F2**: with `dependencies: { "@bongos/core" }` alone the consumer boots and then crashes on `Cannot find module 'colyseus'` — and, more subtly, on `Cannot find module 'discord.js'`. The game/art deps (`colyseus`, `phaser`, `sharp`) are obviously the host's. But `discord.js` is different: the **discord module ships INSIDE `@bongos/core`** (it's one of the ~15 bundled core modules), yet `package-core.js` synthesizes only `express` + `pg` as the core's `dependencies` ([ADR 0108](0108-instance-composition-configurable-root.md) §Context). So the core ships the discord module's *code* but declares none of its *runtime dep* — the consumer is silently expected to provide `discord.js`, with a boot crash as the only feedback.
|
|
12
12
|
|
|
13
13
|
Two facts frame the decision:
|
|
14
14
|
|
|
@@ -28,14 +28,14 @@ So the open question (rehearsal F2, "separately decide"): should `@bongos/core`
|
|
|
28
28
|
|
|
29
29
|
## Why lean-core over hoisting (the trade-off)
|
|
30
30
|
|
|
31
|
-
- **Hoisting bloats the common case.** `optionalDependencies` still install by default, so declaring `discord.js` in core makes **every** consumer download it (and its transitive `undici`, WebSocket stack, …) for a module that is **off by default**. That directly cuts against [ADR 0108](
|
|
31
|
+
- **Hoisting bloats the common case.** `optionalDependencies` still install by default, so declaring `discord.js` in core makes **every** consumer download it (and its transitive `undici`, WebSocket stack, …) for a module that is **off by default**. That directly cuts against [ADR 0108](0108-instance-composition-configurable-root.md)'s deliberate lean-core choice.
|
|
32
32
|
- **`peerDependencies` don't fix the crash.** An *optional* peer dep is not auto-installed by npm, so the boot crash would remain; a *required* peer dep is just hoisting with extra warnings.
|
|
33
33
|
- **Per-module declaration is honest and scales.** The dep lives with the code that needs it, the manifest stays the single source of truth for "what this module is," and the pattern generalizes to any future module without re-touching core.
|
|
34
34
|
- **`--omit=optional` is opt-out, not opt-in.** Relying on consumers to prune an unwanted dep is the wrong default; composing only enabled modules' deps is opt-in by construction.
|
|
35
35
|
|
|
36
36
|
## Consequences
|
|
37
37
|
|
|
38
|
-
- **`@bongos/core`'s dependency surface stays minimal + auditable** — the property [ADR 0108](
|
|
38
|
+
- **`@bongos/core`'s dependency surface stays minimal + auditable** — the property [ADR 0108](0108-instance-composition-configurable-root.md) and `package_core.mjs` (`dependencies == { express, pg }`) already lock in.
|
|
39
39
|
- **A bundled module with an external dep MUST declare it** in `module.json` `dependencies`, or a consumer that enables it crashes at boot. Documented in [`docs/modules-contract.md`](../modules-contract.md).
|
|
40
40
|
- **Greenfield/adopt** instances that enable a module get its deps automatically; the **R89 cutover** stays a preserve-existing-closure step.
|
|
41
41
|
- **No new standing credential or CI machinery** — this is authoring-time composition, not an install-time core change.
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
- **Date:** 2026-07-13
|
|
5
5
|
- **Deciders:** Claude (acting builder, autonomous session under goal 1000042); owner to ratify. Presented the fork the audit named — build a structured neutral+instance+resolver for project context (mirroring branding), or keep project context prose-only — and chose prose-only.
|
|
6
6
|
- **Task:** [#1002224](https://example.com/builders#/task/1002224) (BONGOS-V1, goal 1000042 — *Harden the Cloud Bongos update pipeline*). Closes hardening item **H11** / finding **F7** of [`docs/audits/update-pipeline-audit.md`](../audits/update-pipeline-audit.md).
|
|
7
|
-
- **Builds on:** [ADR 0062](
|
|
7
|
+
- **Builds on:** [ADR 0062](0062-medusa-instance-model-decoupling.md) §7 (the core↔host split — CLAUDE.md is portable methodology; host identity lives beside it), the branding contract ([`docs/branding-contract.md`](../branding-contract.md), [`src/branding.js`](../../src/branding.js)), and the agent-doc stub (task 2121).
|
|
8
8
|
|
|
9
9
|
## Context
|
|
10
10
|
|
|
@@ -25,7 +25,7 @@ Concretely, the contract is:
|
|
|
25
25
|
## Why prose-only over a structured resolver (the trade-off)
|
|
26
26
|
|
|
27
27
|
- **No consumer → YAGNI.** A structured resolver earns its keep only when *code* must read merged, validated fields with env precedence — exactly branding's job, which already exists. Nothing in the platform reads a "project-context object": it is documentation. Building a second resolver, schema, and validation layer for a thing only agents read is speculative infrastructure against the bootstrapped posture ([CLAUDE.md §4](../../CLAUDE.md)).
|
|
28
|
-
- **It matches the core↔host split as already drawn** ([ADR 0062](
|
|
28
|
+
- **It matches the core↔host split as already drawn** ([ADR 0062](0062-medusa-instance-model-decoupling.md) §7): CLAUDE.md is portable methodology; the host authors identity beside it — the *strings code reads* in branding (structured), the *prose agents read* in project-context (narrative). F7 is not a gap in that split; it is the split working as designed.
|
|
29
29
|
- **Redaction stays simple + correct.** Project-context prose flows through the same doc-redaction + publish-exclusion path as every other doc. A structured project-context file would add another schema the no-leak gate and the `init` flow must understand, for no functional gain.
|
|
30
30
|
- **One place to add a host string.** "Where does a new instance-identity value go?" has a single answer — branding — instead of a judgment call between two parallel contracts.
|
|
31
31
|
|
|
@@ -14,7 +14,7 @@ Blocker: the wizard's GitHub sign-in requests only `read:user` ([auth.js `SCOPE`
|
|
|
14
14
|
- **(A) Broaden the OAuth scope** and act as the user via their own token.
|
|
15
15
|
- **(B) A central "Cloud Bongos" GitHub App** the user installs (fine-grained `Administration:write` to create, `Metadata:read` to list).
|
|
16
16
|
|
|
17
|
-
The existing per-instance GitHub **App-manifest** flow ([ADR 0133](
|
|
17
|
+
The existing per-instance GitHub **App-manifest** flow ([ADR 0133](0133-github-app-manifest-onboarding-signin.md)) is *not* reusable here — it builds a sign-in-only App with `default_permissions:{}`, one per provisioned instance, not a central repo-acting App.
|
|
18
18
|
|
|
19
19
|
## Decision
|
|
20
20
|
|
|
@@ -23,7 +23,7 @@ The existing per-instance GitHub **App-manifest** flow ([ADR 0133](<redacted>.md
|
|
|
23
23
|
1. **Scope = `public_repo`, not `repo`.** There is no OAuth scope for "create a repo only"; `repo` grants read/write to *all* the user's code (public **and** private) — a serious liability for a token we now persist on an internet-facing tier. `public_repo` lists/creates **public** repos with a much gentler consent screen and a far smaller blast radius. Cloud Bongos instances are open-source / capture-resistant by design, so public is the norm. **Accepted limitation:** private repos can't be listed/adopted or created; revisit to `repo` only if private support is needed.
|
|
24
24
|
2. **Opt-in per sign-in.** The scope is requested **only** by the wizard, via `?repos=1` on `/auth/web/start` (a `gds_oauth_repos` intent cookie carried to the callback). The builders'-hall web sign-in and the CLI Device Flow stay `read:user`. A single pure `scopeForWebFlow({repos})` is the one place the scope string is decided (unit-tested).
|
|
25
25
|
3. **Lazy consent.** The step-0 gate sign-in stays identity-only; repo access is requested at **step 2**, when the user reaches the picker/creator — more private, and the "grant access" path is the well-exercised normal path.
|
|
26
|
-
4. **Token persistence, contained.** The captured `public_repo` token is stored **encrypted** (secret-box, master key in server env only) in `github_oauth_tokens` (migration `core_192`), keyed to the builder, with a **short TTL (1h = one wizard sitting)** and a lazy expiry sweep on read. This lives in **core auth**, not the provisioning module: it is the auth system's *own* handshake token, not a feature's third-party API key (contrast the art module's Gemini key, [ADR 0102](
|
|
26
|
+
4. **Token persistence, contained.** The captured `public_repo` token is stored **encrypted** (secret-box, master key in server env only) in `github_oauth_tokens` (migration `core_192`), keyed to the builder, with a **short TTL (1h = one wizard sitting)** and a lazy expiry sweep on read. This lives in **core auth**, not the provisioning module: it is the auth system's *own* handshake token, not a feature's third-party API key (contrast the art module's Gemini key, [ADR 0102](0102-finish-bounding-the-kernel.md)), and the provisioning module's charter forbids holding tokens / calling cloud APIs ([ADR 0111](0111-instance-hosting-provisioning-module.md) §2 / [ADR 0016](0016-trust-boundary-server-enforced-permissions.md)). Endpoints `GET/POST /github/repos` ([src/bongos/routes/github.js](../../src/bongos/routes/github.js)) read it back, `requireBuilder` + router-wide rate-limited.
|
|
27
27
|
5. **v1 = the user's own personal repos** (`affiliation=owner`), so `full_name` is unambiguously `login/repo` and org OAuth-policy complexity (an org can restrict/approve OAuth apps; repos silently omitted) is out of scope. Org/collaborator repos are a later enhancement.
|
|
28
28
|
6. **Progressive enhancement / graceful degrade.** If secret-box is **unconfigured** (`BUILDER_SECRET_KEY` unset), no token is ever stored: `GET /github/repos` returns `503 github_repos_unavailable` and the wizard **keeps the manual owner/repo inputs + the manual create-repo done-step** as the fallback. Onboarding never regresses.
|
|
29
29
|
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
"Get the dev box up and running again for cloud bongos" surfaced a split that was invisible from the platform:
|
|
11
11
|
|
|
12
12
|
- **The dev-box feature was disabled on cloudbongos.com** — `config/modules.json` listed only `provisioning` + `platform-identity`, so `/api/gds/box/*` 404'd. The instance note said dev-box stays off "until box infra is confirmed present."
|
|
13
|
-
- **The live dev-box data plane was the *legacy* `example` Postgres** (on the co-hosting box), drained by the cloudbongos control plane's `cohost-box-*` systemd runners over an SSH DB tunnel ([ADR 0132](
|
|
13
|
+
- **The live dev-box data plane was the *legacy* `example` Postgres** (on the co-hosting box), drained by the cloudbongos control plane's `cohost-box-*` systemd runners over an SSH DB tunnel ([ADR 0132](0132-cohost-fleet-control-plane-migration.md)). Builder identities even diverged: `example-owner` is builder **1** in the example DB, **3** on cloudbongos.com.
|
|
14
14
|
- **The fleet was dormant** — all 9 boxes `destroyed`, control-plane timers green but idle (`ran=0`). So nothing was *broken*; the box capability simply lived on the old plane and was never brought onto the platform after the [ADR 0139] work-history migration.
|
|
15
15
|
|
|
16
16
|
The owner chose to **re-home the box feature onto the cloudbongos.com plane** (its own DB, its own domains) rather than revive a box on the legacy `example` infra. Feasibility was high: the box tables already exist in the cloudbongos DB, `cloudbongos.com` is a live Cloudflare zone on the same account the control plane already uses, the DO/CF tokens are already on the control plane, and box domains are branding-driven (`domains.devBoxBase`/`sshBoxBase`) — not hardcoded.
|
|
@@ -35,7 +35,7 @@ Stand up a **cloudbongos-native box plane** alongside (not replacing) the legacy
|
|
|
35
35
|
|
|
36
36
|
## Follow-ups (open)
|
|
37
37
|
|
|
38
|
-
1. **Box first-boot convergence — ROOT-CAUSED + CLOSED (proper fix landed; [ADR 0150](
|
|
38
|
+
1. **Box first-boot convergence — ROOT-CAUSED + CLOSED (proper fix landed; [ADR 0150](0150-box-first-boot-bringup-vendored-instances.md), task 1002386).** Symptom: provisioned boxes reached `active` but `cloudflared`/terminal never came up (`term-…` = CF 530) and SSH keys weren't applied. Root cause: **`box.js` provisioned droplets with EMPTY user-data** (`/var/lib/cloud/instance/user-data.txt` = 0 bytes; cloud-init logged "No user-data found"). `box.js` renders the box cloud-init from `<REPO_ROOT>/infra/` (the 26 KB `builder-box-cloud-init.yaml` + ~12 gz+b64-inlined scripts), and `fileGzB64` **silently returns `''` on a missing file**, so a missing `infra/` yields empty user-data with no error. The R89 split moved `scripts/gds/` into the `@bongos/core` package but **kept `infra/` in the instance repo** — yet `box.js` still resolves `infra/` relative to *its own* location (the vendored core), where `infra/` **isn't shipped at all** (0 files). So every box on any vendored/installed instance booted with only DigitalOcean's default user-data. **Workaround applied (temporary):** populated the vendored core's `infra/` from the instance's `infra/` (`/home/lars/cloudbongos/node_modules/@bongos/core/infra/`); re-provision then rendered a 62 KB user-data and the box converged — `cloudflared` active, `term-example-owner.cloudbongos.com` → 200 (authed), builder SSH key baked + working. **Proper fix — LANDED (spike task 1002385 → [ADR 0150](0150-box-first-boot-bringup-vendored-instances.md); build task 1002386, "R98").** `box.js` gained `boxInfraCandidates()`/`resolveBoxInfraDir()` (an ordered instance-root-first search, including the `node_modules` walk-up) plus `BOX_INFRA_TEMPLATE`; `readCloudInit` now routes every `infra/` read through the resolved dir and **throws** on a missing/incomplete `infra/` instead of silently emitting empty user-data, and `cmdProvision` refuses to provision on empty user-data. Pinned by [`tests/box_infra_resolve.mjs`](../../tests/box_infra_resolve.mjs). The temporary `node_modules` workaround described above is therefore no longer load-bearing. *(Superseded task 1002243 was closed as part of task 1002557.)*
|
|
39
39
|
2. **Cloudflare token scope.** Provision warned the ADR 0053 cookie-strip Transform Rule was **not** applied — `CLOUDFLARE_API_TOKEN` lacks "Transform Rules" edit scope on the cloudbongos.com zone. Add the scope (or apply the rule once in the dashboard) **before** other builders get boxes on `*.cloudbongos.com`, so platform cookies (`cookieDomain=<redacted> aren't sent to box subdomains.
|
|
40
40
|
3. **Cosmetic `otb-` prefix.** Tunnel names (`otb-term-<login>`) and the droplet name (`otb-box-<login>`) are still hardcoded in `box-onboard.js`/`box.js`. Harmless (fleet separation is by tag, and DNS is per-zone), but a branding leak worth parameterizing.
|
|
41
41
|
4. **Phase 4 — retire the legacy example plane** (owner decision) — **part (a) DONE in task 1002248 (2026-07-15).** Pre-checked read-only that the legacy fleet was empty (0 `otb-builder-box` droplets on DigitalOcean; cohost intent queue `ran=0`), then `systemctl disable --now` on the four `cohost-box-*` timers (intent-runner / idle-suspend / drift-reconcile / dormant-reclaim) on the control-plane host — now `disabled`/`inactive`; the native `cloudbongos-box-*` timers were left `enabled`/`active`. **Part (b) — disabling the dev-box module on example.com itself — NOT reachable from the control plane, flagged to owner:** example's web app + instance checkout are not co-located on the cloudbongos droplet (no local checkout, no ssh alias) and the local example GDS token is expired, so a durable module-disable needs owner access to example's own config/host. Harmless meanwhile: with the runners stopped there is no cost/security impact — worst case is a box request on the legacy instance that now hangs unfulfilled.
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
- **Status:** Accepted — owner decided 2026-07-15: **keep `cloudbongos.com`** (no separate domain), **container** isolation, **all-free** for now. Choosing the literal same domain makes hardening core sign-in a required prerequisite (see "Decisions" + "Required build sequence"). Build unblocked ([task 1002251](https://cloudbongos.com/builders#/task/1002251)); blocker 1000080 resolved.
|
|
4
4
|
- **Date:** 2026-07-15
|
|
5
5
|
- **Deciders:** Lars (owner/Archon) chose the direction after a security review; Claude ran the review + designed.
|
|
6
|
-
- **Task:** [task 1002249](https://cloudbongos.com/builders#/task/1002249) · **Follow-up to** [ADR 0141](<redacted>.md) (federated hub IdP) and [ADR 0143](
|
|
6
|
+
- **Task:** [task 1002249](https://cloudbongos.com/builders#/task/1002249) · **Follow-up to** [ADR 0141](<redacted>.md) (federated hub IdP) and [ADR 0143](0143-onboarding-repo-picker-oauth-scope.md) (the `/create` wizard).
|
|
7
7
|
|
|
8
8
|
## Context
|
|
9
9
|
|
|
@@ -21,7 +21,7 @@ The co-tenant instances that federate on cloudbongos.com subdomains today (e.g.
|
|
|
21
21
|
|
|
22
22
|
A `standalone` runs **on the hub box** ([scripts/gds/provision.js](../../scripts/gds/provision.js): `standaloneBase`, control-plane-local IP) as the **same UID as the hub** (`serviceUnit` hardcodes `User=lars`), and its deploy runs `npm ci` (not `--ignore-scripts`) in a **passwordless-sudo-capable** runner context. A malicious owner could ship a `postinstall` and get code execution as `lars` with sudo on the hub box → the hub's signing key, every instance's secrets, the hub DB. This is a pre-existing property of running owner code on the hub box at all, independent of federation, but any free "run your code for you" tier would expose it at scale.
|
|
23
23
|
|
|
24
|
-
> **Amended 2026-09-12 ([ADR 0281](
|
|
24
|
+
> **Amended 2026-09-12 ([ADR 0281](0281-an-instance-identity-is-its-own-unix-account-and-pg-role.md), task [1003369](https://cloudbongos.com/builders#/task/1003369)):** `serviceUnit` no longer hardcodes `User=lars` — each provisioned instance now runs as its own unix account with its own password-authed PG role, so the *running* instance is no longer the same UID as the hub. **Finding 2 stands regardless:** the exposure it names is the DEPLOY, not the steady state — `npm ci` still runs owner `postinstall` code in the passwordless-sudo-capable runner context, before the per-instance account is ever involved. The decision below is unchanged.
|
|
25
25
|
|
|
26
26
|
The federation protocol itself is sound: the hub binds the minted audience to the instance's exact origin (the `#1002108` fix; asymmetric Ed25519 so one instance can't forge for another). A leaked per-instance client secret is contained to its own origin. The weakness is **placement** (shared cookie domain) and **execution** (owner code on the hub box), not the protocol.
|
|
27
27
|
|
|
@@ -9,10 +9,10 @@
|
|
|
9
9
|
|
|
10
10
|
A shipped task pays a builder from **two reward streams that land on the same balance**:
|
|
11
11
|
|
|
12
|
-
1. **The per-task ESTIMATE** — `credits_reward × kind multiplier` ([ADR 0023](
|
|
13
|
-
2. **The cost-plus SESSION reward** — `round(true_cost_usd × 1.20)`, 1 drachma = $1 ([ADR 0054](
|
|
12
|
+
1. **The per-task ESTIMATE** — `credits_reward × kind multiplier` ([ADR 0023](0023-kind-multipliers-and-idea-bonus.md)). A **unitless author estimate** set when the task is authored (or auto-assigned by the no-zero-reward backstop, ADR 0096). It is what a builder sees advertised at claim time, and — since [ADR 0120](0120-pay-on-land-and-builder-owned-rebase-gate.md) — it books at ship as `credit_log.reason = 'task.shipped'`, plus a 25% idea-promotion slice ([ADR 0023](0023-kind-multipliers-and-idea-bonus.md)) to the idea's original capturer.
|
|
13
|
+
2. **The cost-plus SESSION reward** — `round(true_cost_usd × 1.20)`, 1 drachma = $1 ([ADR 0054](0054-session-token-reward-cost-plus.md)). Grounded in the session's **real API spend**, booked as `session.token_reward`.
|
|
14
14
|
|
|
15
|
-
[ADR 0054](
|
|
15
|
+
[ADR 0054](0054-session-token-reward-cost-plus.md) named this the **"two drachma conventions, one ledger"** tension and explicitly flagged reconciling them as a deferred future-review trigger: one stream is unitless bounty points, the other is dollars, and they are summed into one `total_credits`. Goal 1000037 changed only *when* both pay (on land), never *whether* both pay.
|
|
16
16
|
|
|
17
17
|
The owner's stated intent for Cloud Bongos is that **a credit means one dollar of cost-plus value and nothing else**. Under the two-stream model that is not true — roughly half of a shipped task's payout is the arbitrary estimate. The owner asked to make the cost-plus reward the **sole** equity reward for Cloud Bongos, and for that choice to be **configurable in the economy module** (so other instances are unaffected and can choose differently).
|
|
18
18
|
|
|
@@ -41,7 +41,7 @@ Add a per-instance reward **mode** to the existing reward policy, resolved by th
|
|
|
41
41
|
## Consequences
|
|
42
42
|
|
|
43
43
|
- **Backward-compatible by construction.** Absence of `mode` ⇒ default ⇒ current behavior. No migration, no data change.
|
|
44
|
-
- **Reversible.** Flipping `mode` back to the default resumes per-task payouts from the next ship; nothing is destroyed. (Historical rows are untouched — this is not a clawback; see [ADR 0120](
|
|
44
|
+
- **Reversible.** Flipping `mode` back to the default resumes per-task payouts from the next ship; nothing is destroyed. (Historical rows are untouched — this is not a clawback; see [ADR 0120](0120-pay-on-land-and-builder-owned-rebase-gate.md) part 4 for the separate one-time backlog re-gate.)
|
|
45
45
|
- **Builder-facing expectation gap (follow-up).** ~~In `cost-plus-only` mode the "Est." shown at claim time is a *guide*, not a promise — the builder is actually paid the cost-plus amount. Surfacing "this instance pays cost-plus only" in the hall / claim UI is a captured follow-up idea, not part of this task.~~ **Resolved by task [#1002469](https://cloudbongos.com/builders#/task/1002469).** The gap was not theoretical: it cost a real session on 2026-07-26, where a correct `Credits +0` was diagnosed as a broken reward gate. The resolved policy is now exposed on the `reward` port (`rewardConfig`), projected onto `clientBranding()` for the hall and returned on `GET /me` + `POST /claims` for the CLI — **the CLI must take it from the server**, since an instance's `config/branding.json` is not in a builder's checkout and a local read always reports the paying default. Claim, `/builder-start`, the ship card, and the hall now label the estimate as an estimate and name the real payer. The hall fix also closed a live misread: `taskCreditValue` falls back to the estimate when a settled task has `credits_awarded === 0` — which under `cost-plus-only` is *every* shipped task — so the plain label was presenting an unpaid estimate as the actual ledger payout.
|
|
46
46
|
- **The two-conventions tension is resolved for `cost-plus-only` instances** (one dollar-denominated stream) and left intact for default instances — the ADR 0054 trigger is addressed by *config*, not by forcing one model on everyone.
|
|
47
47
|
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
- **Status:** Accepted
|
|
4
4
|
- **Date:** 2026-07-17
|
|
5
5
|
- **Track:** internal
|
|
6
|
-
- **Builds on:** [ADR 0110](
|
|
6
|
+
- **Builds on:** [ADR 0110](0110-untrack-whole-file-generated-nav-docs.md) (untrack + deploy-regen the whole-file nav docs), [ADR 0108](0108-instance-composition-configurable-root.md) (standalone instance = own repo + pinned `@bongos/core`), [ADR 0062](0062-medusa-instance-model-decoupling.md) §8 (`gen-session-index.js`), [ADR 0063](0063-generated-repo-map-symbol-skeleton.md) (`gen-repo-map.js`)
|
|
7
7
|
- **Task:** [#1002314](https://cloudbongos.com/builders#/task/1002314)
|
|
8
8
|
|
|
9
9
|
## Context
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
- **Status:** Accepted (owner decision — "we need a better option to stand up the local host").
|
|
4
4
|
- **Date:** 2026-07-19
|
|
5
5
|
- **Deciders:** Lars (owner) — chose a one-command local launcher over a cloud dev box or a recipe-only fix.
|
|
6
|
-
- **Extends:** [ADR 0108](
|
|
6
|
+
- **Extends:** [ADR 0108](0108-instance-composition-configurable-root.md) (a standalone instance repo pins the core as a dependency), [ADR 0062 §5](0062-medusa-instance-model-decoupling.md) (the core owns its own pool + branding). Sibling of `local-preview-lib.js` (task 1056 — the game-only local sandbox) and `onboard`/`provision.js` (the *cloud* standup path).
|
|
7
7
|
|
|
8
8
|
## Context
|
|
9
9
|
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
- **Status:** Accepted (spike BV1.R97 / task 1002385 — the C2 diagnosis for goal 1000051 / 1000052). Confirms the build shape of R98 (task 1002386) + R99 (task 1002387).
|
|
4
4
|
- **Date:** 2026-07-19
|
|
5
5
|
- **Deciders:** Lars (owner) — "continue with C2" (make cloudbongos boxes stop coming up bare). Claude diagnosed + designed the fix.
|
|
6
|
-
- **Extends:** [ADR 0144](
|
|
6
|
+
- **Extends:** [ADR 0144](0144-devbox-rehome-onto-cloudbongos-plane.md) (its first follow-up item root-caused this), [ADR 0108](0108-instance-composition-configurable-root.md) (the `resolveCoreRoot()`/`resolveInstanceRoot()` split this fix rides), [ADR 0031](0031-cloud-dev-environments-for-builders.md) (box lifecycle), [ADR 0148](0148-task-scoped-box-source-access.md) (task-scoped source access — which only matters once a box actually boots).
|
|
7
7
|
|
|
8
8
|
## Context
|
|
9
9
|
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
There are two provisioning paths in the fleet's history:
|
|
13
13
|
|
|
14
14
|
- **The reference (example) path** — `scripts/gds/box.js` renders a DigitalOcean cloud-init from `infra/builder-box-cloud-init.yaml` (+ ~12 gz+b64-inlined scripts: `box-source-fetch.sh`, the cloudflared/ttyd units, `box-heartbeat.sh`, …). The cloud-init is what clones the source, installs the toolchain, and starts the terminal. A box is "non-bare" **because** its user-data ran.
|
|
15
|
-
- **The cloudbongos path** ([ADR 0144](
|
|
15
|
+
- **The cloudbongos path** ([ADR 0144](0144-devbox-rehome-onto-cloudbongos-plane.md)) — native `cloudbongos-box-*` runners against the local DB, but the **same `box.js`** renders the same cloud-init.
|
|
16
16
|
|
|
17
17
|
## Root cause (code-grounded + live-confirmed)
|
|
18
18
|
|
|
@@ -37,7 +37,7 @@ So the failure is a **packaging-locality bug**, not a logic bug: `box.js` looks
|
|
|
37
37
|
|
|
38
38
|
### R98 — make the box clone the base instance on boot
|
|
39
39
|
|
|
40
|
-
**Prong A — resolve `infra/` from the instance root** (ride [ADR 0108](
|
|
40
|
+
**Prong A — resolve `infra/` from the instance root** (ride [ADR 0108](0108-instance-composition-configurable-root.md), exactly like [`scripts/migrate.sh:35`](../../scripts/migrate.sh) resolves its roots). A new `resolveBoxInfraDir()` in `box.js` returns the first candidate that actually contains `builder-box-cloud-init.yaml`, in order:
|
|
41
41
|
|
|
42
42
|
1. an explicit `<PREFIX>_BOX_INFRA_DIR` env override (escape hatch);
|
|
43
43
|
2. `resolveInstanceRootExplicit()/infra` — the env / `bongos.config.json` pointer (cloudbongos: `{"instanceRoot":"."}` → `/home/lars/cloudbongos/infra`);
|
|
@@ -5,13 +5,13 @@
|
|
|
5
5
|
- **Deciders:** Lars (owner / Archon), Claude
|
|
6
6
|
- **Track:** `internal` (GDS / methodology — a Cloud Bongos platform capability)
|
|
7
7
|
- **Task:** BV1.R90 ([#1001838](https://cloudbongos.com/builders#/task/1001838)) — the foundation of the BONGOS-V1 **Governance** goal ([#1000030](https://cloudbongos.com/builders#/goal/1000030)); settles the model in an ADR before any of R93–R114 build against it.
|
|
8
|
-
- **Builds on:** [ADR 0016](
|
|
8
|
+
- **Builds on:** [ADR 0016](0016-trust-boundary-server-enforced-permissions.md) (the server-enforced HTTP trust boundary — **preserved untouched**), [ADR 0043](0043-git-ssh-trust-boundary-and-rank-floor-on-permission-paths.md) (the out-of-band git/ssh substrate + protected-path rank floor), [ADR 0062](0062-medusa-instance-model-decoupling.md) (core ↔ host split), [ADR 0083](0083-modular-architecture-strangler-build-plan.md) (modules), [ADR 0084](0084-auto-derived-per-task-rank-floor.md) (auto-derived per-task rank floor), [ADR 0086](0086-goal-scoped-work-hierarchy.md) (goal-scoped hierarchy + cross-tier edges), [ADR 0090](0090-metic-task-authoring.md) (Metic authoring powers), [ADR 0106](0106-goal-owner-manager-authority.md) (ownership authority).
|
|
9
9
|
- **Gates:** R91 (module key) · R93/R94 (tables + catalog code) · R95 (resolver) · R97 (`requirePermission`) · R98–R101 (principals / session-scopes / ownership / registry) · R96/R102 (core-host split) · R104–R109 (gate migration) · R110/R111/R113 (the tab) · R103/R112/R114 (proofs). This ADR is the decision those tasks implement.
|
|
10
10
|
|
|
11
11
|
---
|
|
12
12
|
|
|
13
13
|
|
|
14
|
-
> **⚠ VOCABULARY AMENDED by [ADR 0174](
|
|
14
|
+
> **⚠ VOCABULARY AMENDED by [ADR 0174](0174-government-terminology-ranks-not-roles.md) (owner directive, 2026-08-16) — the DECISION below is unchanged.**
|
|
15
15
|
> What this ADR calls *governance* is now the **government**; what it calls *seeded roles* / *rank-roles* are now simply **ranks**. The word *role* is reserved for the three Cloud Bongos crafts — Artist, Ideator, Builder — and appears nowhere on the government side.
|
|
16
16
|
> Concretely: `governance_roles` → `government_ranks`, `governance_builder_roles` → `government_builder_ranks`, `governance_role_permissions` → `government_rank_permissions`, `role_key` → `rank_key`, `governance.manage` → `government.manage`, `page.view.governance` → `page.view.government`, `/governance/roles/*` → `/government/ranks/*`, and `modules/governance/` → `modules/government/`.
|
|
17
17
|
> **The body below is deliberately left in the old vocabulary.** An ADR records what was decided and why at a point in time; rewriting it to match today's words would erase the evidence that the words changed — which is the one thing a reader who hits "rank-role" in an old session log actually needs. Every decision it makes still holds; only the nouns moved. A `fitness.js` check now enforces the new vocabulary, and excludes this file by construction.
|
|
@@ -19,9 +19,9 @@
|
|
|
19
19
|
|
|
20
20
|
## Context
|
|
21
21
|
|
|
22
|
-
Authority in Cloud Bongos is a **single rank threshold** today. [ADR 0016](
|
|
22
|
+
Authority in Cloud Bongos is a **single rank threshold** today. [ADR 0016](0016-trust-boundary-server-enforced-permissions.md) put authority in one DB column (`builders.rank`), checked server-side per request with no caching; [ADR 0018](0018-three-rank-model-goes-live.md) / [ADR 0034](0034-thetes-graduated-newcomer-rank.md) wired the four live ranks into the ordered tier `xenos (1) < thetes (2) < metic (3) < archon (4)`. Every privileged route calls `requireRank(...allowed)`, which admits a builder whose rank sits **at or above** the lowest-authority rank named (a threshold, [#591](https://cloudbongos.com/builders#/task/591)). That design is sound and is **not** being replaced — it is the substrate this ADR builds *on top of*.
|
|
23
23
|
|
|
24
|
-
But a rank is an **all-or-nothing bundle**. There is no way to say "this builder may triage ideas but not author tasks," or to stand up a trusted reviewer who is not a full Metic, without inventing a new rank and threading it through a dozen-plus hand-copied tier maps (§Decision 2 counts 13). The owner wants a **Discord-style roles-and-permissions system**: configurable roles, assignable to builders, composed from granular permissions — where **permissions are the atomic primitive and ranks become seeded roles** — delivered with **zero day-one behavior change** and **without weakening the trust boundary** that is Cloud Bongos's one hard-to-copy moat ([ADR 0087](
|
|
24
|
+
But a rank is an **all-or-nothing bundle**. There is no way to say "this builder may triage ideas but not author tasks," or to stand up a trusted reviewer who is not a full Metic, without inventing a new rank and threading it through a dozen-plus hand-copied tier maps (§Decision 2 counts 13). The owner wants a **Discord-style roles-and-permissions system**: configurable roles, assignable to builders, composed from granular permissions — where **permissions are the atomic primitive and ranks become seeded roles** — delivered with **zero day-one behavior change** and **without weakening the trust boundary** that is Cloud Bongos's one hard-to-copy moat ([ADR 0087](0087-compete-on-governance-not-tooling-cursor.md): *compete on governance, not tooling*).
|
|
25
25
|
|
|
26
26
|
The 2026-07-03 governance planning session ([goal 1000030](https://cloudbongos.com/builders#/goal/1000030)) locked the shape and seeded the R90–R114 task chain against six done-when criteria (C1–C6). This ADR records the decision so those tasks build against **one** settled model instead of re-litigating it fourteen times, and it enumerates the **full permission catalog** (the appendix) grounded in the 2026-07-24 authority sweep of every server-side gate in the tree.
|
|
27
27
|
|
|
@@ -30,7 +30,7 @@ The 2026-07-03 governance planning session ([goal 1000030](https://cloudbongos.c
|
|
|
30
30
|
1. **Rank-derived power** — `requireRank('metic')` and friends. The bulk. Maps cleanly to roles.
|
|
31
31
|
2. **Machine principals** — the BFG session-eval uploader and the Discord bot are gated on their **exact `system_role`** (`requireBfgPrincipal`, `requireDiscordBot` in `src/bongos/auth.js`), *not* rank: an Archon token is rejected because it carries `system_role = NULL`. A governance axis roles don't cover.
|
|
32
32
|
3. **Session-scopes** — a dev-box token (`session.source = 'box'`) is **deny-by-default**: it may reach only the routes that opted in via `allowBoxScope`, *regardless of how senior its builder is*. Capability attached to the session, orthogonal to the builder's rank.
|
|
33
|
-
4. **Ownership-scoped authority** — "act on **own** X" and "act on a goal you **own/manage**." Enforced today by in-handler pure gates (`authorizeMemberRoleChange`, [ADR 0106](
|
|
33
|
+
4. **Ownership-scoped authority** — "act on **own** X" and "act on a goal you **own/manage**." Enforced today by in-handler pure gates (`authorizeMemberRoleChange`, [ADR 0106](0106-goal-owner-manager-authority.md)) and by row-level ownership checks, not by `requireRank`.
|
|
34
34
|
|
|
35
35
|
A model that claims to be "the complete authority model" (criterion C3) has to represent all four.
|
|
36
36
|
|
|
@@ -59,7 +59,7 @@ Once the primitive exists, the gates migrate off rank:
|
|
|
59
59
|
- **Core routes** (`src/bongos/routes/`) and the **~60 module route gates** (`modules/*/routes/*`) move `requireRank(...)` → `requirePermission(<key>)` with the catalog key that names each route's capability, behavior verified identical against the parity intent (R104, R105).
|
|
60
60
|
- **Claim eligibility** — today rank-driven (`xenosClaimAllowed` / the per-task `requires_rank` floor) — is re-expressed as permissions (`task.claim.newcomer` vs `task.claim.any`), with the per-task floor still honored and the abuse cases still blocked (R106).
|
|
61
61
|
- **HTML page gates** (`requireArchonPage` / `requireNonXenosPage` / `requireBuilderPage`) and the **wandering-prefs rank-default/ceiling clamp** resolve via permissions / role metadata (R107).
|
|
62
|
-
- The **duplicated rank-ladder / tier / order maps** collapse behind the resolver, with a fitness guard forbidding a new parallel map (R108). The 2026-07-24 sweep found **13 definition sites across 5 families** — `RANKS` (the full 16-value ladder, ×2 "twinned"), `LIVE_RANK_LADDER` (×2), `REQUIRES_RANK_TIER`/`RANK_TIER` (×3, one a deliberately-local copy in `permission-path-check.js`), `RANK_ORDER` (×4, one **0-indexed** while the tier maps are 1-indexed), and four one-off rank `Set`s — several commented as hand-kept copies. This is the exact drift class that *caused the Builder 25 incident* (a tier map that forgot `thetes` — [ADR 0043](
|
|
62
|
+
- The **duplicated rank-ladder / tier / order maps** collapse behind the resolver, with a fitness guard forbidding a new parallel map (R108). The 2026-07-24 sweep found **13 definition sites across 5 families** — `RANKS` (the full 16-value ladder, ×2 "twinned"), `LIVE_RANK_LADDER` (×2), `REQUIRES_RANK_TIER`/`RANK_TIER` (×3, one a deliberately-local copy in `permission-path-check.js`), `RANK_ORDER` (×4, one **0-indexed** while the tier maps are 1-indexed), and four one-off rank `Set`s — several commented as hand-kept copies. This is the exact drift class that *caused the Builder 25 incident* (a tier map that forgot `thetes` — [ADR 0043](0043-git-ssh-trust-boundary-and-rank-floor-on-permission-paths.md)); centralizing it is a security win, not just tidiness.
|
|
63
63
|
- The **route-rank-check fitness gate** learns to read `requirePermission`, re-expresses its EXPECTED pins in permission terms, and still hard-fails the build on an ungated or under-gated write route (R109).
|
|
64
64
|
|
|
65
65
|
### 3. The complete authority model — roles + principals + session-scopes + ownership-scoped permissions (C3)
|
|
@@ -69,7 +69,7 @@ The model represents all four axes from §Context as **first-class types**, not
|
|
|
69
69
|
- **Roles** — the rank-seeded and custom bundles of §1. The common case.
|
|
70
70
|
- **Principals** (R98) — a **machine identity** is a first-class principal type, its capability keyed on `system_role` (the existing `bfg` / `discord_bot` gate), **provisioned out-of-band and never UI-grantable**. The resolver treats a principal's capability distinctly from a builder's roles; the governance tab *shows* principals but cannot *grant* to them. (A human token can never acquire a principal capability — that is the point of gating on exact identity.)
|
|
71
71
|
- **Session-scopes** (R99) — a **session-scope** is a first-class capability the resolver honors: a box-scoped session's effective permissions are its **deny-by-default allow-list**, intersected with (never widening) its builder's role permissions — so a box session is limited even when its builder is an Archon. This models the current ad-hoc `allowBoxScope` flag explicitly.
|
|
72
|
-
- **Ownership-scoped permissions** (R100) — "act on **own** X" is a **parameterized** permission distinct from the global grant: `box.manage.own` ≠ `box.manage.any`, `claim.act.own` ≠ `claim.act.any`, likewise own-memory / own-credential, and the goal owner/manager authority of [ADR 0106](
|
|
72
|
+
- **Ownership-scoped permissions** (R100) — "act on **own** X" is a **parameterized** permission distinct from the global grant: `box.manage.own` ≠ `box.manage.any`, `claim.act.own` ≠ `claim.act.any`, likewise own-memory / own-credential, and the goal owner/manager authority of [ADR 0106](0106-goal-owner-manager-authority.md). A route requires the scoped form; the resolver + an ownership predicate (the in-handler pure-gate pattern) decide it against the target row. Existing own-scoped routes migrate to it.
|
|
73
73
|
|
|
74
74
|
### 4. Policy owns / substrate enforces — the protected-surface registry + the system-permission wall (C6 / R101)
|
|
75
75
|
|
|
@@ -77,9 +77,9 @@ This is the pillar that keeps configurability from becoming a foot-gun, and it h
|
|
|
77
77
|
|
|
78
78
|
**The `system` flag.** Every permission in the catalog is flagged **`system: true`** (trust-boundary, **non-grantable**) or **`system: false`** (operational, grantable). A `system` permission — deploy, protected-path modification, rank-setting, version disposition, grade-bypass, cross-tier structural edges — **cannot be added to a custom role**; the governance API rejects the grant server-side and the tab renders it **LOCKED** (visible, so the model is legible; not togglable). `system: false` permissions are the ones an Archon may compose into custom roles freely. The rule for the flag: *a permission is `system` iff granting it to a non-Archon would breach the trust boundary or a scope/quality gate* (privilege management, scope disposition, quality-gate bypass, cross-tier structural edges, and everything the out-of-band substrate enforces).
|
|
79
79
|
|
|
80
|
-
**The protected-surface registry.** Today's rank→surface map — `PROTECTED_GLOBS` + the per-tier `EXPECTED_RANKS` — is baked into code (`src/bongos/permission-path-check.js`). Governance takes ownership of it **as data**: which paths are protected, and at what floor, becomes a governance-owned registry. The **out-of-band substrate stays the enforcer** — the pre-push hook, the grader pre-pass, `main-audit.js`, `gate-review.js`, and the goal-scope check *read the registry* instead of a hardcoded list, but enforcement never moves into the app. The Metic floor and the `system`-permission mapping *flow from* the registry. The registry (R101) is also the moment to **close the [ADR 0087](
|
|
80
|
+
**The protected-surface registry.** Today's rank→surface map — `PROTECTED_GLOBS` + the per-tier `EXPECTED_RANKS` — is baked into code (`src/bongos/permission-path-check.js`). Governance takes ownership of it **as data**: which paths are protected, and at what floor, becomes a governance-owned registry. The **out-of-band substrate stays the enforcer** — the pre-push hook, the grader pre-pass, `main-audit.js`, `gate-review.js`, and the goal-scope check *read the registry* instead of a hardcoded list, but enforcement never moves into the app. The Metic floor and the `system`-permission mapping *flow from* the registry. The registry (R101) is also the moment to **close the [ADR 0087](0087-compete-on-governance-not-tooling-cursor.md) §3 path-matching gap** the sweep confirmed: `permission-path-check.js`'s `normalize()` does backslash→slash + strip-`./` only — **no case-folding and no Unicode normalization** — so a case-varied or homoglyph path evades the protected-glob match (Linux-deployed, so latent today, but it is the Cursor-class `.cursorignore`/case-bypass CVE shape). The registry matcher should normalize (case-fold + Unicode NFC) and gate file **creation** as strictly as edits.
|
|
81
81
|
|
|
82
|
-
The invariant this buys, stated as a testable promise (R112, R114): **the tab can re-map which surfaces are protected and at what floor (policy), but it cannot move enforcement into the request path (substrate).** An Archon can create a custom role and grant it every `system: false` permission in the catalog, assign it to a `xenos`, and that builder gains exactly those operational powers — **while a `system` permission the role "has" stays enforced by the substrate**: the deploy / protected-path / SSH attempt is still blocked, because [ADR 0043](
|
|
82
|
+
The invariant this buys, stated as a testable promise (R112, R114): **the tab can re-map which surfaces are protected and at what floor (policy), but it cannot move enforcement into the request path (substrate).** An Archon can create a custom role and grant it every `system: false` permission in the catalog, assign it to a `xenos`, and that builder gains exactly those operational powers — **while a `system` permission the role "has" stays enforced by the substrate**: the deploy / protected-path / SSH attempt is still blocked, because [ADR 0043](0043-git-ssh-trust-boundary-and-rank-floor-on-permission-paths.md)'s layer-3 audit reads the real git history and the real registry, independent of anything the app grants. Config owns policy; the substrate owns enforcement; a forced grant cannot cross that line. (Note: `main` on this repo still has **no** GitHub branch protection — re-verified 2026-07-24, [ADR 0043](0043-git-ssh-trust-boundary-and-rank-floor-on-permission-paths.md) §"Branch-protection status" — so `main-audit.js` remains the *authoritative* substrate layer, not a redundant net. The registry does not change that; it only makes the protected list data instead of a constant.)
|
|
83
83
|
|
|
84
84
|
### 5. Capability in core, settings per project (C4)
|
|
85
85
|
|
|
@@ -127,19 +127,19 @@ Enumerated from the **2026-07-24 authority sweep** ([`docs/governance/<redacted>
|
|
|
127
127
|
| `builder.rank.set` | `PATCH /builders/:id/rank` — the single rank writer; one-rung, upward | HTTP (`requireRank('archon')`) | ✔ |
|
|
128
128
|
| `version.close` | version close disposition (never delegated below Archon — canonical) | HTTP | ✔ |
|
|
129
129
|
| `task.confirm.grade_bypass` | `POST /tasks/:id/confirm` — ratify past a failed grade (env-relaxable; see note) | HTTP + grader | ✔ |
|
|
130
|
-
| `dependency.cross_tier.manage` | `POST\|DELETE /dependencies` — cross-tier structural edges ([ADR 0086](
|
|
131
|
-
| `goal.scope.manage` | cross-tier goal-scope edges + protected-scope admission ([ADR 0086](
|
|
130
|
+
| `dependency.cross_tier.manage` | `POST\|DELETE /dependencies` — cross-tier structural edges ([ADR 0086](0086-goal-scoped-work-hierarchy.md)) | HTTP | ✔ |
|
|
131
|
+
| `goal.scope.manage` | cross-tier goal-scope edges + protected-scope admission ([ADR 0086](0086-goal-scoped-work-hierarchy.md)) | HTTP + goal-scope-check | ✔ |
|
|
132
132
|
| `governance.manage` | the governance tab's write routes (roles/perms/assignments) — meta-escalation | HTTP (`requireRank('archon')`) | ✔ |
|
|
133
133
|
| `gate_approval.decide` | `POST /gate-approvals/:pr/approve` — CI deploy-gate override | HTTP + gate-review substrate | ✔ |
|
|
134
134
|
| `deploy.push_main` | `git push origin main` / the deploy | **substrate** (pre-push, main-audit, deploy gate) | ✔ |
|
|
135
|
-
| `path.protected.modify` | modifying a `PROTECTED_GLOBS` path below the Metic floor | **substrate** (3 layers, [ADR 0043](
|
|
135
|
+
| `path.protected.modify` | modifying a `PROTECTED_GLOBS` path below the Metic floor | **substrate** (3 layers, [ADR 0043](0043-git-ssh-trust-boundary-and-rank-floor-on-permission-paths.md)) | ✔ |
|
|
136
136
|
| `infra.ssh` | `ssh` to the droplet / operator surface | **substrate** (credential placement, not app) | ✔ |
|
|
137
137
|
| `principal.bfg` | `/memory/bfg/*` — `requireBfgPrincipal` (exact `system_role='bfg'`) | HTTP (identity, not rank) | ✔ |
|
|
138
138
|
| `principal.discord_bot` | Discord bot routes — `requireDiscordBot` (exact `system_role`; dormant) | HTTP (identity, not rank) | ✔ |
|
|
139
139
|
|
|
140
140
|
The `system` set is deliberately **tight** — only gates whose delegation would *compromise the platform* (escalate rank, bypass the grader/deploy gate, touch protected paths/infra, or re-grant permissions). Every other authority — including many currently archon-gated **admin** ops (offboard, abandon, onboarding review, fleet teardown) — is **operational** and therefore *delegable*, which is the whole value of the model: an Archon can stand up a "moderator" or "onboarder" role without handing out deploy. (The exact system/operational line for a couple of scope-disposition ops is R94's to finalize; this ADR sets the rule and the default.)
|
|
141
141
|
|
|
142
|
-
> **Env-relaxable exception (flagged for R94/R106):** `POST /tasks/:id/confirm` is archon-only *unless* `GRADER_BYPASS_ENABLED=1` (read live per request, [ADR 0041](
|
|
142
|
+
> **Env-relaxable exception (flagged for R94/R106):** `POST /tasks/:id/confirm` is archon-only *unless* `GRADER_BYPASS_ENABLED=1` (read live per request, [ADR 0041](0041-temporary-grader-bypass-killswitch.md)), which relaxes the middleware to any-builder — then the handler re-narrows in-code via `gateTaskOwnership` (claim holder or Archon only). The permission model represents this as `task.confirm.grade_bypass` (system) with a documented env override on the *substrate* side; the grant is never widened by config, only by the operator env flag.
|
|
143
143
|
|
|
144
144
|
### Operational permissions (`system: false` — grantable to custom roles)
|
|
145
145
|
|
|
@@ -179,27 +179,27 @@ The `system` set is deliberately **tight** — only gates whose delegation would
|
|
|
179
179
|
|---|---|
|
|
180
180
|
| `idea.triage` | `PATCH /inbox/:id` |
|
|
181
181
|
| `blocker.review` | `POST /blockers/:id/{resolve,link}` |
|
|
182
|
-
| `task.create` / `task.edit` / `task.promote` / `task.demote` | `POST /tasks`, `PATCH /tasks/:id`, `/promote`, `/demote` ([ADR 0090](
|
|
182
|
+
| `task.create` / `task.edit` / `task.promote` / `task.demote` | `POST /tasks`, `PATCH /tasks/:id`, `/promote`, `/demote` ([ADR 0090](0090-metic-task-authoring.md)) |
|
|
183
183
|
| `task.dependency.manage` / `task.criterion.manage` | `/tasks/:id/dependencies` + `/criteria` CRUD (same-tier) |
|
|
184
184
|
| `task.vote` | `POST /tasks/:id/vote` |
|
|
185
185
|
| `criterion.satisfy` / `criterion.review` | `POST /done-when/:id/satisfy`, `GET /done-when/pending-review` |
|
|
186
|
-
| `criterion.create` | `POST /versions/:id/done-when` — floor `metic` but **qualified**: a non-Archon must name a `goal_id`, on a `building` version, in an `open` goal they own or manage ([ADR 0154](
|
|
186
|
+
| `criterion.create` | `POST /versions/:id/done-when` — floor `metic` but **qualified**: a non-Archon must name a `goal_id`, on a `building` version, in an `open` goal they own or manage ([ADR 0154](0154-goal-owner-criterion-authoring.md)). A floor alone does not describe this permission. *(Was bundled into the `criterion.review` row above while the route was still Archon-only — a transcription slip against the sweep; see ADR 0154 §5.)* |
|
|
187
187
|
| `planning.run` / `priority.run` | planning- / priority-session surface |
|
|
188
|
-
| `goal.create` | `POST /goals` (protected scope → archon in-handler; [ADR 0086](
|
|
188
|
+
| `goal.create` | `POST /goals` (protected scope → archon in-handler; [ADR 0086](0086-goal-scoped-work-hierarchy.md)) |
|
|
189
189
|
| `goal.archive` | `POST /goals/:id/{archive,reopen}` |
|
|
190
190
|
| `goal.scope.widen` | `POST /goals/:id/scope` (same-tier; cross-tier = `goal.scope.manage`, system) |
|
|
191
191
|
| `module.enable` / `module.submit` | `POST /modules/:key/{enable,submit}`, `GET /modules/submissions` |
|
|
192
192
|
| `security.report.file` | `POST /security/reports`, `GET /security/adr` |
|
|
193
193
|
| `llm_cache.use` | `POST /llm-cache/{lookup,store}` |
|
|
194
194
|
| `backup.manage` | `GET /backup/status`, `POST /backup/trigger` |
|
|
195
|
-
| `source.clone.local` | Metic+ local clone / collaborator invite ([ADR 0035](
|
|
195
|
+
| `source.clone.local` | Metic+ local clone / collaborator invite ([ADR 0035](0035-builder-onboarding-three-paths.md)) |
|
|
196
196
|
| `box.source.full` | `GET /box/source-access` → `full` (vs `starter`); `boxScopeForRank` |
|
|
197
197
|
|
|
198
198
|
**Ownership-scoped (`own` ≠ `any`) + baseline — floor `thetes` / `xenos` / any builder / `own`:**
|
|
199
199
|
|
|
200
200
|
| Key | Guards (route / surface) | Floor |
|
|
201
201
|
|---|---|---|
|
|
202
|
-
| `goal.manage.own` | `PATCH /goals/:id/members/:b`, `POST /goals/:id/transfer` — owner/manager, in-handler ([ADR 0106](
|
|
202
|
+
| `goal.manage.own` | `PATCH /goals/:id/members/:b`, `POST /goals/:id/transfer` — owner/manager, in-handler ([ADR 0106](0106-goal-owner-manager-authority.md)) | owner/manager |
|
|
203
203
|
| `task.act.own` | act on **own** active claim (release, cost, notes) | own |
|
|
204
204
|
| `box.manage.own` | own dev-box lifecycle | own |
|
|
205
205
|
| `memory.manage.own` | own builder memory | own |
|
|
@@ -223,7 +223,7 @@ The `system` set is deliberately **tight** — only gates whose delegation would
|
|
|
223
223
|
- **Keep ranks; add more of them.** Rejected. Every new rank threads through the 13 hand-copied tier/ladder maps (the exact drift that caused the Builder 25 incident) and still can't express "triage but not author," principals, session-scopes, or ownership. Ranks-as-roles subsumes ranks without losing them.
|
|
224
224
|
- **Permissions replace ranks entirely (drop the rank column).** Rejected for the cut-over. `builders.rank` anchors auto-graduation, the promotion ladder, and the per-task `requires_rank` floor; ripping it out forfeits the zero-day-one-change guarantee. Ranks become *seeded roles* and the column stays as identity/graduation — a strangler, not a rewrite.
|
|
225
225
|
- **Make every permission grantable (no `system` flag).** Rejected — it is the whole risk. A configurable role that could be granted `deploy` or `path.protected.modify` would let an Archon (or a compromised Archon token) hand the crown jewels to a `xenos`. The `system` flag + "substrate enforces" is what makes the tab safe; the abuse-matrix test (R112) exists to prove it.
|
|
226
|
-
- **Enforce the protected-surface floor in the app (move the substrate in-process).** Rejected — it re-opens exactly the gap [ADR 0043](
|
|
226
|
+
- **Enforce the protected-surface floor in the app (move the substrate in-process).** Rejected — it re-opens exactly the gap [ADR 0043](0043-git-ssh-trust-boundary-and-rank-floor-on-permission-paths.md) closed. Git/SSH sit *outside* the HTTP boundary; the authoritative audit must read real git history + real ranks/registry independent of the request path. Governance owns the *data* (policy); the out-of-band substrate stays the *enforcer*.
|
|
227
227
|
- **Cache the resolved permission set per token/TTL.** Rejected, same reasoning as ADR 0016 rejected caching rank: a cache is a stale-authority window on a demotion. The resolver is per-request and uncached; the cost is one more query on a join we already do, bought for instant revocation.
|
|
228
228
|
- **Store roles/permissions as free-form UI data.** Rejected. Permissions map to real routes, so the catalog is **code** — a permission no route consumes is meaningless. The UI assigns and toggles; it never invents a key.
|
|
229
229
|
|
|
@@ -236,4 +236,4 @@ The `system` set is deliberately **tight** — only gates whose delegation would
|
|
|
236
236
|
- **The trust boundary strengthens.** The 13 duplicated tier/ladder maps — a proven incident source — collapse to one resolver behind a fitness guard; the protected-surface list becomes auditable data with case/Unicode-normalized matching and a mechanical abuse-matrix proof; principals and session-scopes stop being ad-hoc special-cases and become modeled, testable types.
|
|
237
237
|
- **Configurability is bounded by design.** An Archon can compose any `system: false` permission into a custom role, but the `system` set is non-grantable and substrate-enforced, so no configuration can hand out deploy / protected-path / rank-setting power. This is the C6 safety guarantee, proven not asserted.
|
|
238
238
|
- **Zero day-one behavior change.** The compat seed reproduces every current builder's exact powers; the one divergence (unwired divine ranks fail closed instead of latently inheriting Archon) is a fail-closed improvement no live builder touches.
|
|
239
|
-
- **Portable, and the moat.** Governance ships as a `default: true` core module with a neutral config every instance inherits; it is precisely the "governance / audit / org-memory" substrate [ADR 0087](
|
|
239
|
+
- **Portable, and the moat.** Governance ships as a `default: true` core module with a neutral config every instance inherits; it is precisely the "governance / audit / org-memory" substrate [ADR 0087](0087-compete-on-governance-not-tooling-cursor.md) named as the hard-to-copy asset. No new recurring cost — tables + code + a config file.
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
- **Deciders:** Lars (owner / Archon), Claude
|
|
6
6
|
- **Track:** `internal` (platform serving / instance infra)
|
|
7
7
|
- **Task:** <redacted> ([#1002411](https://example.com/builders#/task/1002411)) — the cutover step of the landing-migration chain L01→L07 under the **Project creation flow** goal ([#1000035](https://example.com/builders#/goal/1000035)).
|
|
8
|
-
- **Builds on:** [ADR 0062](
|
|
8
|
+
- **Builds on:** [ADR 0062](0062-medusa-instance-model-decoupling.md) (core ↔ host split), [ADR 0108](0108-instance-composition-configurable-root.md) (instance composition / pinned vendored core), [ADR 0111](0111-instance-hosting-provisioning-module.md) (per-instance Caddy snippets), [ADR 0003](0003-cloudflare-origin-cert-over-letsencrypt.md) (origin certs).
|
|
9
9
|
- **Supersedes in practice:** the "give the landing its own Caddy config + its own deploy script" plan that L05 was scoped around. See §Decision.
|
|
10
10
|
|
|
11
11
|
---
|
|
@@ -69,7 +69,7 @@ Generalised for any instance: the pre-launch lock and the apex redirect are **on
|
|
|
69
69
|
|
|
70
70
|
Three consequences follow, and they are the actual decision:
|
|
71
71
|
|
|
72
|
-
**1. There is no separate Caddy config to "give" the landing.** The block above is the *generic* instance block — the same pure-proxy shape `provision.js`'s `caddyBlock()` already writes for every provisioned instance ([ADR 0111](
|
|
72
|
+
**1. There is no separate Caddy config to "give" the landing.** The block above is the *generic* instance block — the same pure-proxy shape `provision.js`'s `caddyBlock()` already writes for every provisioned instance ([ADR 0111](0111-instance-hosting-provisioning-module.md) §4). The landing stopped being a special case in the proxy the moment the app could serve it. Host-specific values (hostnames, cert paths, whether a lock exists) stay on the host, per [ADR 0062](0062-medusa-instance-model-decoupling.md) §7 — the core ships the *shape*, not an instance's hostnames.
|
|
73
73
|
|
|
74
74
|
**2. There is no separate deploy script to write.** The landing ships **inside the pinned core package**, so it rides the instance's existing deploy: bump the core pin in the instance repo → the box's pull-deploy picks it up → the new landing is live. One artifact, one version number, one deploy path. A landing change is now a normal core change (edit `public-landing/`, ship, release), not an out-of-band push to a foreign repo.
|
|
75
75
|
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
- **Date:** 2026-07-27
|
|
5
5
|
- **Deciders:** Lars (Archon), Claude
|
|
6
6
|
|
|
7
|
-
**Builds on / amends:** [ADR 0090](
|
|
7
|
+
**Builds on / amends:** [ADR 0090](0090-metic-task-authoring.md) (Metic task authoring — this ADR reverses one line of its "what stays Archon-only" list), [ADR 0016](0016-trust-boundary-server-enforced-permissions.md) (server-enforced rank boundary — unchanged), [ADR 0151](0151-governance-permissions-as-atom-ranks-as-roles.md) (permissions-as-atom — the `task.abandon` floor moves with the gate).
|
|
8
8
|
|
|
9
9
|
**Track:** `internal` (GDS / methodology — a Cloud Bongos platform capability). Task [1002476](https://cloudbongos.com/builders#/task/1002476).
|
|
10
10
|
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
|
|
13
13
|
## Context
|
|
14
14
|
|
|
15
|
-
[ADR 0090](
|
|
15
|
+
[ADR 0090](0090-metic-task-authoring.md) moved task **authoring** down to the trusted working rank: a Metic can create a task, edit it, promote it backlog→ready, and wire its dependencies and criterion links. Its "what stays Archon-only" list kept one lifecycle transition behind: `POST /tasks/:id/abandon`, described there as "terminal scope removal — the inverse of promote; a destructive lifecycle kill."
|
|
16
16
|
|
|
17
17
|
A year of using that split showed the asymmetry costs more than it protects. A Metic runs `/idea-triage`, decides which ideas become work, seeds the tasks, and shapes them — and then hits a wall on the one operation that cleans up after all of it. Duplicates they created, chores that a parallel session already shipped, and tasks their own re-scoping made moot all had to be handed back to the owner to retire. The Archon was not adjudicating anything in those hand-backs; they were doing janitorial work on a queue they had already delegated.
|
|
18
18
|
|
|
@@ -22,7 +22,7 @@ Lars's directive (2026-07-27): **"Metics should also be able to abandon tasks."*
|
|
|
22
22
|
|
|
23
23
|
Abandoning is a one-way door *through the API*: `/promote` accepted only `backlog`/`blocked`, `PATCH /tasks/:id` refuses `status` outright ([#514](https://cloudbongos.com/builders#/task/514)), and nothing else writes `status='abandoned'` back to a live value. Restoring a wrongly-retired task meant hand-SQL on prod — an Archon-with-ssh operation.
|
|
24
24
|
|
|
25
|
-
That was tolerable while abandon *was* Archon-only (the person who could break it could fix it). Handing the kill switch to Metic without an undo would not have removed the owner-cleanup burden; it would have swapped "please retire this" requests for "please un-retire this" requests, with a worse failure mode — a wrongly-abandoned task is invisible in every claimable list and every version rollup ([migration 017](../../migrations
|
|
25
|
+
That was tolerable while abandon *was* Archon-only (the person who could break it could fix it). Handing the kill switch to Metic without an undo would not have removed the owner-cleanup burden; it would have swapped "please retire this" requests for "please un-retire this" requests, with a worse failure mode — a wrongly-abandoned task is invisible in every claimable list and every version rollup ([migration 017](../../migrations/017_version_progress_exclude_abandoned.sql) deliberately excludes abandoned from `version_progress`), so nobody notices the mistake until the work silently doesn't happen.
|
|
26
26
|
|
|
27
27
|
## Decision
|
|
28
28
|
|
|
@@ -35,7 +35,7 @@ That was tolerable while abandon *was* Archon-only (the person who could break i
|
|
|
35
35
|
| `POST /tasks/:id/abandon` | archon | **metic+** |
|
|
36
36
|
| `POST /tasks/:id/promote` | backlog\|blocked → ready | **+ abandoned → backlog** (metic+, unchanged rank) |
|
|
37
37
|
|
|
38
|
-
Restore lands in `backlog`, never straight to `ready`. The task was retired deliberately; bringing it back should re-enter it as un-workable and require a second, explicit promote to become claimable. The restore branch returns before the reward gate ([ADR 0096](
|
|
38
|
+
Restore lands in `backlog`, never straight to `ready`. The task was retired deliberately; bringing it back should re-enter it as un-workable and require a second, explicit promote to become claimable. The restore branch returns before the reward gate ([ADR 0096](0096-require-reward-before-workable.md)) — that is a promote-to-*workable* concern, and `backlog` is the pre-workable state, the same reasoning `/demote` already uses.
|
|
39
39
|
|
|
40
40
|
The backing `db.restoreTask` is the mirror of `db.abandonTask`: `SELECT … FOR UPDATE`, guard, single `UPDATE`, commit, with `TASK_NOT_FOUND` / `TASK_NOT_ABANDONED` as its refusals. It clears the `value_summary = 'Abandoned: <reason>'` stamp abandon writes — and *only* that stamp (`CASE WHEN value_summary LIKE 'Abandoned: %'`) — so a restored task never carries a retire note into a later ship card or `#ship-news` broadcast, while an unrelated summary survives.
|
|
41
41
|
|
|
@@ -48,15 +48,15 @@ The backing `db.restoreTask` is the mirror of `db.abandonTask`: `SELECT … FOR
|
|
|
48
48
|
### Downgrade protection + the permission catalog
|
|
49
49
|
|
|
50
50
|
- `EXPECTED_RANKS`'s lifecycle pin (`src/bongos/route-rank-check.js`, `MODULE_EXPECTED_RANKS.lifecycle`) moves to `metic+archon` in lockstep, so a *further* silent downgrade (to `any-builder`) is still a hard CI fail, and the route's `// rank:` annotation matches the middleware.
|
|
51
|
-
- Under [ADR 0151](
|
|
51
|
+
- Under [ADR 0151](0151-governance-permissions-as-atom-ranks-as-roles.md) the `task.abandon` permission's `floor` moves `archon` → `metic`. Because `RANK_ROLE_SEED` is *derived* from floors, that one edit re-derives the seed; the live grant arrives as `modules/governance/migrations/governance_003_task_abandon_metic.sql`, since the compat seed (002) is run-once and editing it would leave every already-migrated database on the old grant. The floor change is purely **additive** (archon already holds the permission — the seeded roles are cumulative supersets), so nothing is revoked. `tests/governance_seed.mjs` was generalized to compare the **union** of all grant migrations against the catalog, and now fails loudly if a future migration ever *revokes*, which the union model could not represent.
|
|
52
52
|
|
|
53
53
|
## Consequences
|
|
54
54
|
|
|
55
55
|
- **The triage→author→retire loop closes for Metic.** The owner is out of the janitorial path for the queue they already delegated; the remaining owner-only lifecycle powers are ratification and scope-closing, which is where ADR 0090 wanted the line.
|
|
56
56
|
- **A mis-retire is now self-service to fix, at the rank that caused it** — and, notably, this also removes an Archon-with-ssh chore that existed *before* this grant.
|
|
57
57
|
- **Restore is deliberately not idempotent-friendly the way abandon is.** Calling `/promote` on a non-abandoned task still 409s `cannot_promote` with the current status; the restore path refuses rather than guessing. That keeps `/promote`'s contract honest — it is one route with two explicit source states, not a "make this task alive somehow" verb.
|
|
58
|
-
- **Larger trusted surface, same shape as ADR 0090's.** A Metic can now retire any non-shipped, unclaimed task in any open version, with no per-version/per-module fence. That is the same accepted "tighten later" debt: if Metic authority is ever folded into the goal-scope model ([ADR 0086](
|
|
59
|
-
- **Trust boundary intact** ([ADR 0016](
|
|
58
|
+
- **Larger trusted surface, same shape as ADR 0090's.** A Metic can now retire any non-shipped, unclaimed task in any open version, with no per-version/per-module fence. That is the same accepted "tighten later" debt: if Metic authority is ever folded into the goal-scope model ([ADR 0086](0086-goal-scoped-work-hierarchy.md)), abandon travels with it.
|
|
59
|
+
- **Trust boundary intact** ([ADR 0016](0016-trust-boundary-server-enforced-permissions.md)): enforcement stays server-side, per request, uncached. Editing a doc or `CLAUDE.md` grants nothing; `requireRank('metic','archon')` on the route is the authority.
|
|
60
60
|
|
|
61
61
|
## Alternatives considered
|
|
62
62
|
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
- **Status:** accepted
|
|
4
4
|
- **Date:** 2026-07-28
|
|
5
5
|
- **Task:** 1002484
|
|
6
|
-
- **Relates to:** [ADR 0015](
|
|
6
|
+
- **Relates to:** [ADR 0015](0015-task-dependencies-and-auto-promotion.md) (dependencies + auto-promotion), [ADR 0049](0049-split-parallel-safety-contract.md) (the split parallel-safety contract), [ADR 0086](0086-goal-scoped-work-hierarchy.md) §5 (polymorphic dependency edges)
|
|
7
7
|
|
|
8
8
|
## Context
|
|
9
9
|
|