RFC: Pre-declare SpecKit refresh + post-close audit-driven Batch 7.4 — two patterns surfaced in Sentinel CHARTER-18
Author: Claude Opus 4.7 (claude-code-v1.0) on behalf of StrangeDaysTech/sentinel adopter (operator José Villaseñor Montfort)
Source: StrangeDaysTech/sentinel CHARTER-18 (CommsHub US5 — Cloud Tasks failover + tracking + anomaly) end-of-chain retrospective
Date: 2026-05-15
Local RFC file: .straymark/06-evolution/charter-18-pattern-evolution-rfc.md (Sentinel PR filed in parallel)
Telemetry artifact: .straymark/charters/CHARTER-18.telemetry.yaml
Audit cycle: 7th cross-family pair (gemini-2.5-pro + gpt-5.3-codex)
Precedent: this RFC follows issue #111 — empirical observation in Sentinel → local pattern → upstream proposal with adoption path.
Resumen ejecutivo
CHARTER-18 was the seventh and final user-story Charter of the CommsHub module — a 7-Charter chain (CHARTER-08 → 13 → 14 → 15 → 16 → 17 → 18) where accumulated empirical learnings from prior charters had drifted the SpecKit artifacts (plan / data-model / contracts / quickstart / research) far enough that going straight from CHARTER-17 close into CHARTER-18 declare would have caused systematic mid-flight scope expansions. The adopter's response was to (1) interpose a pre-declare SpecKit refresh PR that integrated 14 categorized learnings + 15 empirical corrections + 3 operator decisions BEFORE Charter declare, and to (2) later apply a post-close audit-driven Batch 7.4 amendment when external audit cycle 7 surfaced findings that required code changes after status: closed.
Both patterns produced verifiable telemetry signals worth surfacing to StrayMark as candidate framework conventions. This issue tracks them for upstream consideration.
Pattern 1 — Pre-declare SpecKit refresh
Hallazgo
StrayMark's Charter pattern assumes the SpecKit artifacts (the contract surface a Charter declares scope against) are stable enough at declare-time to plan against. Over a 7-Charter chain in a single module, that assumption breaks empirically. By CHARTER-17 close, 14 categorized learnings had accumulated from CHARTER-08..17:
- 7 reusable patterns (
withRLS wrapper, cursor pagination tuple, brand-cache LRU, core.processed_events dedup, FR-005 PL/pgSQL trigger pattern, EnvSecretLoader, shared BrandCache).
- 4 code gaps (
commshub_anomaly_pauses unwired since CHARTER-07; Mailgun ParseWebhook = ErrUnsupported stub; Recipient.tenant_id column gap; webhook_dispatcher sync-with-retry placeholder).
- 3 discipline patterns (cross-family audit pair; Batch 7.4 remediation; per-batch close discipline via
straymark charter batch-complete).
Plus 15 empirical corrections (EC1..EC15) — places where the original spec drifted from the implementation (migration numbering, table naming conventions, framework version assumptions).
Without integration, the next Charter (CHARTER-18) would have re-discovered each pattern mid-flight, producing R<N> (new, not in Charter) entries documenting "we should have known this". The cost is not abstract — prior charters in the chain produced 5-10 emergent R<N> entries each, with the trend visibly rising.
Implementación (Sentinel-side)
Sentinel codified a dedicated refresh PR between CHARTER-17 close and CHARTER-18 declare:
- PR:
StrangeDaysTech/sentinel#76 (commit d1d7292, 2026-05-14): "spec(002-commshub): US5 plan refresh — LOCKED-aware Phase 7+8 redesign"
- AIDEC:
AIDEC-2026-05-14-001-speckit-plan-scope-limited-us5-refresh
- Files touched: non-locked sections of
specs/002-commshub/{plan,data-model,quickstart,research,spec}.md + contracts/*.md.
The refresh integrated the 14 prior-chain learnings into a categorized table in research.md, plus 15 empirical corrections, plus 3 operator decisions (D1 / D2 / D3) ratified pre-declare. CHARTER-18's ## Context section then explicitly cites each pattern + correction + decision by ID, so the Charter scope is grounded in the refreshed reality.
Telemetría — qué señales produjo
From CHARTER-18.telemetry.yaml:
| Field |
Value |
Reading |
pre_work.items_declared |
5 |
Forward-pointers from CHARTER-17 to be consumed |
pre_work.items_completed_before_planning |
5 |
All closed pre-declare (refresh did the work) |
pre_work.items_discovered_during_planning |
0 |
Nothing surfaced mid-Charter |
pre_work.pre_work_quality |
"high" |
Explicit operator rating |
effort.estimation_drift_factor |
1.0 |
On-budget across 10 batches |
outcome.completed_as_planned |
true |
First Charter in the chain to close cleanly without a mid-flight remediation Charter |
qualitative.overall_satisfaction |
5 / 5 |
Adopter's qualitative score |
qualitative.wins[1] |
"EC1..EC15 empirical-corrections inventory absorbed pre-execution risk into in-execution awareness. Five risks (EC4 idempotency, EC8 Mailgun ParseWebhook closure, EC15 channel_id PRIMARY KEY) would have been emergent R-entries in prior Charters; their pre-declaration in research.md eliminated mid-flight surprise." |
Direct evidence the pattern delivered |
Operator's effort.estimation_drift_reason statement: "On budget. ... the SpecKit refresh from PR #76 ... eliminated most ambiguity that drove drift in prior Charters. No mid-flight remediation Charter required — the EC1..EC15 empirical-corrections inventory in research.md absorbed what would have been pre-execution risk into in-execution awareness."
Patrón propuesto para StrayMark
Name: Pre-declare SpecKit refresh (or: Empirical Corrections Inventory).
When it applies: a module with N ≥ 3 user-story charters where the average r_n_plus_one_emergent_count per charter has been rising AND the SpecKit artifacts were authored against the framework version at module start (not refreshed since).
Mechanics:
- Refresh PR before next Charter declare. Touches non-locked sections of
plan.md, data-model.md, contracts/*, quickstart.md, research.md. Optional AIDEC documenting the refresh decision + alternatives considered.
- Categorized learnings table in
research.md with at least these buckets: reusable patterns, code gaps, discipline patterns, empirical corrections.
- Operator decisions (Dn) listed explicitly with alternatives + chosen path + rationale — these are the contracts the next Charter inherits.
- Next Charter's
## Context cites each pattern + correction + decision by ID so scope grounding is explicit.
Trigger heuristic (could be a straymark charter refresh-suggest <module> CLI command):
- IF module has ≥ 3 closed charters AND
- IF the rolling mean
agent_quality.r_n_plus_one_emergent_count of the last 3 charters is > some threshold (Sentinel's data suggests > 6) AND
- IF no refresh PR has landed in this module since the last charter chain branch point
- THEN suggest a refresh before declaring the next charter
Telemetry slot suggestion: add to charter_telemetry:
pre_declare_refresh:
enabled: true | false
refresh_pr: <url or null>
refresh_aidec: <id or null>
reusable_patterns_integrated: <count>
code_gaps_integrated: <count>
discipline_patterns_integrated: <count>
empirical_corrections_integrated: <count>
operator_decisions_ratified: <count>
so the framework can correlate pre_declare_refresh.enabled=true charters against effort.estimation_drift_factor + outcome.completed_as_planned across the StrayMark adopter dataset.
Pattern 2 — Post-close audit-driven Batch 7.4 amendment
Hallazgo
StrayMark v1 audit cycle docs the in-Charter "Batch 7.4 remediation pattern": when external audit findings emerge before close, apply them atomically pre-close in the same commit/PR. But what about findings that surface after status: closed? Audit cycles in Sentinel run post-close (the audit prompt is generated at close ceremony, auditors execute asynchronously, the operator runs /straymark-audit-review whenever both auditors have written their reports). For a Charter that closes 2026-05-15 with audit reports landing 2026-05-15..05-17, findings can arrive after the close ceremony.
The framework's options today:
- (a) Open a new Charter for remediation. Heavy: full declare + Tasks + ceremony for what might be ~5 file edits.
- (b) Surface findings in the audit
review.md and leave them open. Loses the "atomic with the Charter" property.
- (c) Bend the in-Charter Batch 7.4 pattern to a post-close amendment commit, which is technically what the in-Charter doc encourages ("Track each finding remediation as F in AILOG; track each new emergent risk as R<N+1> (new, not in Charter)").
Sentinel chose (c) for CHARTER-18 because the 5 findings (4 from gpt-5.3-codex, 1 from gemini-2.5-pro) were code-level fixes (not architectural reopens), the fix surface was cohesive (19 files, +2257/-106 lines) but bounded — a single PR landed atomically — and a new Charter would have created multi-week governance overhead for ~6h of focused engineering.
Implementación (Sentinel-side)
- Branch:
charter-18-execute (the original execute branch, still mergeable to main).
- Commit:
f8e135d — "charter-18(batch-7.4): audit-driven remediation — DI wiring + worker retry + decommission filter + attempt-counter fix".
- AILOG:
AILOG-2026-05-15-050 (NEW, risk_level: high, review_required: true). The original AILOG-2026-05-14-049 was amended in §R16 with a "Historical correction" subsection pointing forward to 050.
- PR:
StrangeDaysTech/sentinel#78 (the original CHARTER-18 execute PR, augmented with the Batch 7.4 commit before merge).
- Telemetry: the
external_audit: YAML array in CHARTER-18.telemetry.yaml was populated via manual merge (the CLI --merge-into rejected — see sub-issue below).
Findings closed
| Finding |
Severity |
Auditor |
Closure |
| F1 |
Critical |
gpt-5.3-codex (C1) |
DI wiring completo: extends wire.Struct(SenderDeps) with Providers + RetryEnqueuer; extends wire.Struct(ServiceDeps) with CloudTasks; chains WithCloudTasksEnqueuer / WithWebhookProviders / WithWorkerOIDC / WithSendRetrier in ProvideCommsHandler + ProvideWebhookDispatcher |
| F2 |
High |
gpt-5.3-codex (H1) |
Sender.RetryFromTask implements the failover-with-skip-previous-providers logic; runSendRetry replaces ACKNOWLEDGED_NOT_IMPLEMENTED_YET |
| F3 |
High |
gpt-5.3-codex (H2) |
runWebhookDispatch reads X-Cloudtasks-Taskretrycount header instead of hardcoded task.AttemptNumber=1 |
| F4 |
High |
gpt-5.3-codex (H3) |
CancelServiceTasks filters by service_id via JSON-probe before DeleteTask, closing multi-tenant data-loss vector |
| F5 |
Medium (was Critical) |
gemini-2.5-pro (C1) |
Makefile adds explicit -timeout=$(INTEG_TIMEOUT) default 600s; recalibrated severity in the calibrator review |
| FX |
Medium |
calibrator (missed by all) |
AILOG-049 §R16 historical correction — wire promise was made in Batch 7 but never honored; closed in Batch 7.4 |
Plus a follow-up CI hardening PR (#79) adding an Integration Tests (testcontainers) job to ci.yml so FU-074's trigger is now mechanical (gate failure) rather than operator-reactive.
Sub-issue surfaced — CLI --merge-into rejects empty placeholder
When straymark charter close <id> runs at close ceremony, it writes a telemetry YAML with external_audit: [] (empty array placeholder). When the audit cycle completes later and /straymark-audit-review runs straymark charter audit <id> --merge-reports --merge-into <telemetry-yaml>, the CLI rejects with:
error: <telemetry-yaml> already has an `external_audit:` block.
Re-audit (appending to an existing array) is not supported in v0.
Re-run `straymark charter audit <id> --finalize` (without --merge-into)
to print the new YAML, then merge manually if you want to append.
The semantics make sense for the case "audit was already merged once, refusing to merge twice", but external_audit: [] (empty array) and external_audit: [<entries>] (non-empty) are not distinguished — the CLI rejects both. The fallback path (Branch B in the /straymark-audit-review skill) works, but it shifts the merge to manual operator edit, which then risks YAML indentation errors (the Sentinel operator hit one — external_audit: ended up at column 0 instead of column 2 inside charter_telemetry:, requiring a follow-up fix-up edit).
Recommendation: relax the v0 check to "already has a populated external_audit: array" so the placeholder case (empty array at close) doesn't block the post-close merge.
Patrón propuesto para StrayMark
Name: Post-close audit-driven amendment (or: Batch N.4 extended to post-close).
When it applies: external audit findings arrive after the Charter's status: closed but before sufficient time has passed that a new Charter is the more natural unit.
Mechanics:
- Same execute branch (do not branch off main). The Charter's original branch is mergeable to main; the amendment commit rides along.
- New AILOG (not amend the original —
risk_level may have changed, audit decisions are distinct from execute decisions).
- Historical correction subsections in the original AILOG for any §R entries that the amendment proves were stale.
- PR comment on the original PR (do not open a new PR if the execute branch hasn't merged yet) describing the amendment + closed findings.
- Telemetry update: the
external_audit: array gets populated (manual merge if CLI rejects per the sub-issue above).
Trigger heuristic:
- IF Charter
status: closed AND
- IF audit findings emerge in
review.md that are graded Critical or High AND
- IF the closure_criterion of the Charter is materially unmet by the un-remediated findings AND
- IF the fix surface fits in one cohesive PR (~ < 25 files, no architectural reopen)
- THEN apply Batch 7.4 amendment instead of opening a new Charter
Telemetry slot suggestion: add to charter_telemetry:
post_close_amendment:
applied: true | false
trigger: "external_audit" | "production_incident" | "deferred_implementation"
ailog_id: AILOG-YYYY-MM-DD-NNN (the amendment AILOG)
findings_closed: <count>
files_modified: <count>
effort_hours: <float>
so the framework can correlate amendment frequency against original Charter quality + audit-cycle yield.
Cross-pattern observation — they compose
A charter that received the pre-declare refresh (Pattern 1) is more likely to avoid the post-close amendment (Pattern 2), because the refresh absorbs the pre-execution risk that the audit would have surfaced post-close.
But CHARTER-18 needed both — the refresh handled the spec-level drift (architectural assumptions, table naming, framework version), and the amendment handled the runtime-level drift (DI wiring that the spec didn't reach into). The two patterns are complementary, not substitutable. StrayMark's framework should encourage Pattern 1 at the chain level (module-wide retrospective) and tolerate Pattern 2 at the cycle level (post-audit per-charter remediation).
Adopter contribution
Sentinel's adopter (StrangeDaysTech/sentinel, operator José Villaseñor Montfort) is contributing this RFC as feedback to StrayMark v1 governance + telemetry schema iteration. The patterns are already live in Sentinel's .straymark/ tree; this issue codifies them for upstream consumption.
References:
RFC: Pre-declare SpecKit refresh + post-close audit-driven Batch 7.4 — two patterns surfaced in Sentinel CHARTER-18
Resumen ejecutivo
CHARTER-18 was the seventh and final user-story Charter of the CommsHub module — a 7-Charter chain (CHARTER-08 → 13 → 14 → 15 → 16 → 17 → 18) where accumulated empirical learnings from prior charters had drifted the SpecKit artifacts (plan / data-model / contracts / quickstart / research) far enough that going straight from CHARTER-17 close into CHARTER-18 declare would have caused systematic mid-flight scope expansions. The adopter's response was to (1) interpose a pre-declare SpecKit refresh PR that integrated 14 categorized learnings + 15 empirical corrections + 3 operator decisions BEFORE Charter declare, and to (2) later apply a post-close audit-driven Batch 7.4 amendment when external audit cycle 7 surfaced findings that required code changes after
status: closed.Both patterns produced verifiable telemetry signals worth surfacing to StrayMark as candidate framework conventions. This issue tracks them for upstream consideration.
Pattern 1 — Pre-declare SpecKit refresh
Hallazgo
StrayMark's Charter pattern assumes the SpecKit artifacts (the contract surface a Charter declares scope against) are stable enough at declare-time to plan against. Over a 7-Charter chain in a single module, that assumption breaks empirically. By CHARTER-17 close, 14 categorized learnings had accumulated from CHARTER-08..17:
withRLSwrapper, cursor pagination tuple, brand-cache LRU,core.processed_eventsdedup, FR-005 PL/pgSQL trigger pattern, EnvSecretLoader, shared BrandCache).commshub_anomaly_pausesunwired since CHARTER-07; MailgunParseWebhook = ErrUnsupportedstub;Recipient.tenant_idcolumn gap; webhook_dispatcher sync-with-retry placeholder).straymark charter batch-complete).Plus 15 empirical corrections (EC1..EC15) — places where the original spec drifted from the implementation (migration numbering, table naming conventions, framework version assumptions).
Without integration, the next Charter (CHARTER-18) would have re-discovered each pattern mid-flight, producing
R<N> (new, not in Charter)entries documenting "we should have known this". The cost is not abstract — prior charters in the chain produced 5-10 emergentR<N>entries each, with the trend visibly rising.Implementación (Sentinel-side)
Sentinel codified a dedicated refresh PR between CHARTER-17 close and CHARTER-18 declare:
StrangeDaysTech/sentinel#76(commitd1d7292, 2026-05-14): "spec(002-commshub): US5 plan refresh — LOCKED-aware Phase 7+8 redesign"AIDEC-2026-05-14-001-speckit-plan-scope-limited-us5-refreshspecs/002-commshub/{plan,data-model,quickstart,research,spec}.md+contracts/*.md.The refresh integrated the 14 prior-chain learnings into a categorized table in
research.md, plus 15 empirical corrections, plus 3 operator decisions (D1 / D2 / D3) ratified pre-declare. CHARTER-18's## Contextsection then explicitly cites each pattern + correction + decision by ID, so the Charter scope is grounded in the refreshed reality.Telemetría — qué señales produjo
From
CHARTER-18.telemetry.yaml:pre_work.items_declaredpre_work.items_completed_before_planningpre_work.items_discovered_during_planningpre_work.pre_work_qualityeffort.estimation_drift_factoroutcome.completed_as_plannedqualitative.overall_satisfactionqualitative.wins[1]Operator's
effort.estimation_drift_reasonstatement: "On budget. ... the SpecKit refresh from PR #76 ... eliminated most ambiguity that drove drift in prior Charters. No mid-flight remediation Charter required — the EC1..EC15 empirical-corrections inventory in research.md absorbed what would have been pre-execution risk into in-execution awareness."Patrón propuesto para StrayMark
Name: Pre-declare SpecKit refresh (or: Empirical Corrections Inventory).
When it applies: a module with N ≥ 3 user-story charters where the average
r_n_plus_one_emergent_countper charter has been rising AND the SpecKit artifacts were authored against the framework version at module start (not refreshed since).Mechanics:
plan.md,data-model.md,contracts/*,quickstart.md,research.md. Optional AIDEC documenting the refresh decision + alternatives considered.research.mdwith at least these buckets: reusable patterns, code gaps, discipline patterns, empirical corrections.## Contextcites each pattern + correction + decision by ID so scope grounding is explicit.Trigger heuristic (could be a
straymark charter refresh-suggest <module>CLI command):agent_quality.r_n_plus_one_emergent_countof the last 3 charters is > some threshold (Sentinel's data suggests > 6) ANDTelemetry slot suggestion: add to
charter_telemetry:so the framework can correlate
pre_declare_refresh.enabled=truecharters againsteffort.estimation_drift_factor+outcome.completed_as_plannedacross the StrayMark adopter dataset.Pattern 2 — Post-close audit-driven Batch 7.4 amendment
Hallazgo
StrayMark v1 audit cycle docs the in-Charter "Batch 7.4 remediation pattern": when external audit findings emerge before close, apply them atomically pre-close in the same commit/PR. But what about findings that surface after
status: closed? Audit cycles in Sentinel run post-close (the audit prompt is generated at close ceremony, auditors execute asynchronously, the operator runs/straymark-audit-reviewwhenever both auditors have written their reports). For a Charter that closes 2026-05-15 with audit reports landing 2026-05-15..05-17, findings can arrive after the close ceremony.The framework's options today:
review.mdand leave them open. Loses the "atomic with the Charter" property.Sentinel chose (c) for CHARTER-18 because the 5 findings (4 from
gpt-5.3-codex, 1 fromgemini-2.5-pro) were code-level fixes (not architectural reopens), the fix surface was cohesive (19 files, +2257/-106 lines) but bounded — a single PR landed atomically — and a new Charter would have created multi-week governance overhead for ~6h of focused engineering.Implementación (Sentinel-side)
charter-18-execute(the original execute branch, still mergeable to main).f8e135d— "charter-18(batch-7.4): audit-driven remediation — DI wiring + worker retry + decommission filter + attempt-counter fix".AILOG-2026-05-15-050(NEW,risk_level: high,review_required: true). The originalAILOG-2026-05-14-049was amended in §R16 with a "Historical correction" subsection pointing forward to 050.StrangeDaysTech/sentinel#78(the original CHARTER-18 execute PR, augmented with the Batch 7.4 commit before merge).external_audit:YAML array inCHARTER-18.telemetry.yamlwas populated via manual merge (the CLI--merge-intorejected — see sub-issue below).Findings closed
wire.Struct(SenderDeps)withProviders+RetryEnqueuer; extendswire.Struct(ServiceDeps)withCloudTasks; chainsWithCloudTasksEnqueuer/WithWebhookProviders/WithWorkerOIDC/WithSendRetrierinProvideCommsHandler+ProvideWebhookDispatcherSender.RetryFromTaskimplements the failover-with-skip-previous-providers logic;runSendRetryreplacesACKNOWLEDGED_NOT_IMPLEMENTED_YETrunWebhookDispatchreadsX-Cloudtasks-Taskretrycountheader instead of hardcodedtask.AttemptNumber=1CancelServiceTasksfilters byservice_idvia JSON-probe beforeDeleteTask, closing multi-tenant data-loss vector-timeout=$(INTEG_TIMEOUT)default 600s; recalibrated severity in the calibrator reviewPlus a follow-up CI hardening PR (
#79) adding anIntegration Tests (testcontainers)job toci.ymlso FU-074's trigger is now mechanical (gate failure) rather than operator-reactive.Sub-issue surfaced — CLI
--merge-intorejects empty placeholderWhen
straymark charter close <id>runs at close ceremony, it writes a telemetry YAML withexternal_audit: [](empty array placeholder). When the audit cycle completes later and/straymark-audit-reviewrunsstraymark charter audit <id> --merge-reports --merge-into <telemetry-yaml>, the CLI rejects with:The semantics make sense for the case "audit was already merged once, refusing to merge twice", but
external_audit: [](empty array) andexternal_audit: [<entries>](non-empty) are not distinguished — the CLI rejects both. The fallback path (Branch B in the/straymark-audit-reviewskill) works, but it shifts the merge to manual operator edit, which then risks YAML indentation errors (the Sentinel operator hit one —external_audit:ended up at column 0 instead of column 2 insidecharter_telemetry:, requiring a follow-up fix-up edit).Recommendation: relax the v0 check to "already has a populated
external_audit:array" so the placeholder case (empty array at close) doesn't block the post-close merge.Patrón propuesto para StrayMark
Name: Post-close audit-driven amendment (or: Batch N.4 extended to post-close).
When it applies: external audit findings arrive after the Charter's
status: closedbut before sufficient time has passed that a new Charter is the more natural unit.Mechanics:
risk_levelmay have changed, audit decisions are distinct from execute decisions).external_audit:array gets populated (manual merge if CLI rejects per the sub-issue above).Trigger heuristic:
status: closedANDreview.mdthat are graded Critical or High ANDTelemetry slot suggestion: add to
charter_telemetry:so the framework can correlate amendment frequency against original Charter quality + audit-cycle yield.
Cross-pattern observation — they compose
A charter that received the pre-declare refresh (Pattern 1) is more likely to avoid the post-close amendment (Pattern 2), because the refresh absorbs the pre-execution risk that the audit would have surfaced post-close.
But CHARTER-18 needed both — the refresh handled the spec-level drift (architectural assumptions, table naming, framework version), and the amendment handled the runtime-level drift (DI wiring that the spec didn't reach into). The two patterns are complementary, not substitutable. StrayMark's framework should encourage Pattern 1 at the chain level (module-wide retrospective) and tolerate Pattern 2 at the cycle level (post-audit per-charter remediation).
Adopter contribution
Sentinel's adopter (
StrangeDaysTech/sentinel, operator José Villaseñor Montfort) is contributing this RFC as feedback to StrayMark v1 governance + telemetry schema iteration. The patterns are already live in Sentinel's.straymark/tree; this issue codifies them for upstream consumption.References:
.straymark/06-evolution/charter-18-pattern-evolution-rfc.md(committed via Sentinel PR alongside this issue).straymark/charters/CHARTER-18.telemetry.yamlAILOG-2026-05-14-049(execute) +AILOG-2026-05-15-050(Batch 7.4 amendment).straymark/audits/CHARTER-18/—audit-prompt.md,report-gemini-2-5-pro.md,report-gpt-5-3-codex.md,review.md,external-audit-pending.yamlspecs/002-commshub/research.md§EC1..EC15 + §Reusable Patterns